<commit_before>#include "font2D.hpp"
#include "entity_templates.hpp"
#include "code/ylikuutio/loaders/shader_loader.hpp"
#include "code/ylikuutio/loaders/texture_loader.hpp"

// Include GLEW
#ifndef __GL_GLEW_H_INCLUDED
#define __GL_GLEW_H_INCLUDED
#include <GL/glew.h> // GLfloat, GLuint etc.
#endif

// Include GLM
#ifndef __GLM_GLM_HPP_INCLUDED
#define __GLM_GLM_HPP_INCLUDED
#include <glm/glm.hpp> // glm
#endif

#ifndef __GLM_GTC_MATRIX_TRANSFORM_HPP_INCLUDED
#define __GLM_GTC_MATRIX_TRANSFORM_HPP_INCLUDED
#include <glm/gtc/matrix_transform.hpp>
#endif

// Include standard headers
#include <vector>   // std::vector
#include <cstring>  // std::memcmp, std::strcmp, std::strlen, std::strncmp
#include <stdint.h> // uint32_t etc.
#include <string>   // std::string

namespace ontology
{
    class Universe;

    Font2D::Font2D(
            ontology::Universe* universe_pointer,
            GLuint screen_width,
            GLuint screen_height,
            std::string texture_filename,
            std::string font_texture_file_format)
    {
        // constructor.
        const char* char_font_texture_file_format = font_texture_file_format.c_str();

        // Initialize texture
        if ((std::strcmp(char_font_texture_file_format, "bmp") == 0) || (std::strcmp(char_font_texture_file_format, "BMP") == 0))
        {
            this->texture = loaders::load_BMP_texture(texture_filename);
        }
        else if ((std::strcmp(char_font_texture_file_format, "dds") == 0) || (std::strcmp(char_font_texture_file_format, "DDS") == 0))
        {
            this->texture = loaders::load_DDS_texture(texture_filename);
        }
        else
        {
            printf("Invalid font texture file format: `%s`. Supported font texture file formats: bmp, BMP, dds, DDS.\n", char_font_texture_file_format);
            this->texture = 0;
            return;
        }

        // Initialize VBO
        glGenBuffers(1, &vertexbuffer);
        glGenBuffers(1, &uvbuffer);

        // Initialize Shader
        programID = loaders::load_shaders("TextVertexShader.vertexshader", "TextVertexShader.fragmentshader");

        // Get a handle for our buffers
        vertex_position_in_screenspaceID = glGetAttribLocation(programID, "vertexPosition_screenspace");
        vertexUVID = glGetAttribLocation(programID, "vertexUV");

        // Initialize uniforms' IDs
        Text2DUniformID = glGetUniformLocation(programID, "myTextureSampler");

        // Initialize uniform window width.
        screen_width_uniform_ID = glGetUniformLocation(programID, "screen_width");
        glUniform1i(screen_width_uniform_ID, screen_width);

        // Initialize uniform window height.
        screen_height_uniform_ID = glGetUniformLocation(programID, "screen_height");
        glUniform1i(screen_height_uniform_ID, screen_height);

        this->universe_pointer = universe_pointer;
    }

    Font2D::~Font2D()
    {
        // destructor.

        // Delete buffers
        glDeleteBuffers(1, &vertexbuffer);
        glDeleteBuffers(1, &uvbuffer);

        // Delete texture
        glDeleteTextures(1, &texture);

        // Delete shader
        glDeleteProgram(programID);
    }

    int32_t Font2D::get_number_of_children()
    {
        return -1;
    }

    int32_t Font2D::get_number_of_descendants()
    {
        return -1;
    }

    void Font2D::printText2D(
            GLuint screen_width,
            GLuint screen_height,
            GLuint x,
            GLuint y,
            GLuint text_size,
            GLuint font_size,
            const char* text_char,
            const char* char_font_texture_file_format,
            const char* horizontal_alignment,
            const char* vertical_alignment)
    {
        // If horizontal alignment is `"left"`, each line begins from the same x coordinate.
        // If horizontal alignment is `"left"` and vertical alignment is `"top"`,
        // then there is no need to check the text beforehand for newlines.
        // Otherwise newlines need to be checked beforehand.
        //
        // If horizontal alignment is right, each line ends in the same x coordinate.
        // Newlines need to be checked beforehand.
        uint32_t length = std::strlen(text_char);

        // Count the number of lines.
        uint32_t number_of_lines = 1;

        uint32_t i = 0;

        while (i < length)
        {
            char character = text_char[i++];

            if (character == (char) '\\')
            {
                // OK, this character was backslash, so read the next character.
                character = text_char[i++];

                if (character == 'n')
                {
                    number_of_lines++;
                }
            }
        }

        GLuint current_left_x;
        GLuint current_top_y;

        if (std::strcmp(horizontal_alignment, "left") == 0)
        {
            current_left_x = x;
        }
        else if (std::strcmp(horizontal_alignment, "center") == 0)
        {
            current_left_x = x - 0.5f * length * text_size;
        }
        else if (std::strcmp(horizontal_alignment, "right") == 0)
        {
            current_left_x = x - length * text_size;
        }

        if (std::strcmp(vertical_alignment, "top") == 0)
        {
            current_top_y = y;
        }
        else if (std::strcmp(vertical_alignment, "center") == 0)
        {
            current_top_y = y + 0.5f * number_of_lines * text_size;
        }
        else if (std::strcmp(vertical_alignment, "bottom") == 0)
        {
            current_top_y = y + number_of_lines * text_size;
        }

        // Fill buffers
        std::vector<glm::vec2> vertices;
        std::vector<glm::vec2> UVs;

        i = 0;

        while (i < length)
        {
            // Print to the right side of X (so far there is no check for input length).
            // Print up of Y.
            GLfloat vertex_up_left_x;
            GLfloat vertex_up_left_y;
            GLfloat vertex_up_right_x;
            GLfloat vertex_up_right_y;
            GLfloat vertex_down_left_x;
            GLfloat vertex_down_left_y;
            GLfloat vertex_down_right_x;
            GLfloat vertex_down_right_y;

            char character = text_char[i++];

            if (character == (char) '\\')
            {
                // OK, this character was backslash, so read the next character.
                character = text_char[i++];

                if (character == 'n')
                {
                    // jump to the beginning of the next line.
                    // `"left"` horizontal alignment and `"top"` vertical alignment are assumed.
                    // TODO: implement newline for other horizontal and vertical alignments too!
                    current_left_x = x;
                    current_top_y -= text_size;
                    continue;
                }
            }

            vertex_up_left_x = vertex_down_left_x = current_left_x;
            vertex_up_right_x = vertex_down_right_x = current_left_x + text_size;
            current_left_x += text_size;

            vertex_down_left_y = vertex_down_right_y = current_top_y - text_size;
            vertex_up_left_y = vertex_up_right_y = current_top_y;

            glm::vec2 vertex_up_left = glm::vec2(vertex_up_left_x, vertex_up_left_y);
            glm::vec2 vertex_up_right = glm::vec2(vertex_up_right_x, vertex_up_right_y);
            glm::vec2 vertex_down_left = glm::vec2(vertex_down_left_x, vertex_down_left_y);
            glm::vec2 vertex_down_right = glm::vec2(vertex_down_right_x, vertex_down_right_y);

            vertices.push_back(vertex_up_left);
            vertices.push_back(vertex_down_left);
            vertices.push_back(vertex_up_right);

            vertices.push_back(vertex_down_right);
            vertices.push_back(vertex_up_right);
            vertices.push_back(vertex_down_left);

            float uv_x = (character % font_size) / (GLfloat) font_size;
            float uv_y;

            if ((std::strcmp(char_font_texture_file_format, "dds") == 0) || (std::strcmp(char_font_texture_file_format, "DDS") == 0))
            {
                uv_y = (character / font_size) / (GLfloat) font_size;
            }
            else if ((std::strcmp(char_font_texture_file_format, "bmp") == 0) || (std::strcmp(char_font_texture_file_format, "BMP") == 0))
            {
                // BMP is stored in the file beginning from the bottom line.
                uv_y = 1 - (character / font_size) / (GLfloat) font_size;
            }

            glm::vec2 uv_up_left = glm::vec2(uv_x, uv_y);
            glm::vec2 uv_up_right = glm::vec2(uv_x + (1.0f / (GLfloat) font_size), uv_y);
            glm::vec2 uv_down_right;
            glm::vec2 uv_down_left;

            if ((std::strcmp(char_font_texture_file_format, "dds") == 0) || (std::strcmp(char_font_texture_file_format, "DDS") == 0))
            {
                uv_down_right = glm::vec2(uv_x + (1.0f / (GLfloat) font_size), (uv_y + 1.0f / (GLfloat) font_size));
                uv_down_left = glm::vec2(uv_x, (uv_y + 1.0f / (GLfloat) font_size));
            }
            else if ((std::strcmp(char_font_texture_file_format, "bmp") == 0) || (std::strcmp(char_font_texture_file_format, "BMP") == 0))
            {
                // BMP is stored in the file beginning from the bottom line.
                uv_down_right = glm::vec2(uv_x + (1.0f / (GLfloat) font_size), (uv_y - 1.0f / (GLfloat) font_size));
                uv_down_left = glm::vec2(uv_x, (uv_y - 1.0f / (GLfloat) font_size));
            }
            UVs.push_back(uv_up_left);
            UVs.push_back(uv_down_left);
            UVs.push_back(uv_up_right);

            UVs.push_back(uv_down_right);
            UVs.push_back(uv_up_right);
            UVs.push_back(uv_down_left);
        }

        glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
        glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec2), &vertices[0], GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
        glBufferData(GL_ARRAY_BUFFER, UVs.size() * sizeof(glm::vec2), &UVs[0], GL_STATIC_DRAW);

        // Bind shader
        glUseProgram(programID);

        // Bind texture
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, texture);
        // Set our "myTextureSampler" sampler to user Material Unit 0
        glUniform1i(Text2DUniformID, 0);

        // Set screen width.
        glUniform1i(screen_width_uniform_ID, screen_width);

        // Set screen height.
        glUniform1i(screen_height_uniform_ID, screen_height);

        // 1st attribute buffer : vertices
        glEnableVertexAttribArray(vertex_position_in_screenspaceID);
        glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
        glVertexAttribPointer(vertex_position_in_screenspaceID, 2, GL_FLOAT, GL_FALSE, 0, (void*) 0);

        // 2nd attribute buffer : UVs
        glEnableVertexAttribArray(vertexUVID);
        glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
        glVertexAttribPointer(vertexUVID, 2, GL_FLOAT, GL_FALSE, 0, (void*) 0);

        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

        // Draw call
        glDrawArrays(GL_TRIANGLES, 0, vertices.size());

        glDisable(GL_BLEND);

        glDisableVertexAttribArray(vertex_position_in_screenspaceID);
        glDisableVertexAttribArray(vertexUVID);
    }

    void Font2D::printText2D(PrintingStruct printing_struct)
    {
        if (printing_struct.text.empty())
        {
            printText2D(
                    printing_struct.screen_width,
                    printing_struct.screen_height,
                    printing_struct.x,
                    printing_struct.y,
                    printing_struct.text_size,
                    printing_struct.font_size,
                    printing_struct.text_char,
                    printing_struct.char_font_texture_file_format,
                    printing_struct.horizontal_alignment,
                    printing_struct.vertical_alignment);
        }
        else
        {
            printText2D(
                    printing_struct.screen_width,
                    printing_struct.screen_height,
                    printing_struct.x,
                    printing_struct.y,
                    printing_struct.text_size,
                    printing_struct.font_size,
                    printing_struct.text.c_str(),
                    printing_struct.char_font_texture_file_format,
                    printing_struct.horizontal_alignment,
                    printing_struct.vertical_alignment);
        }
    }

    void Font2D::printText2D(
            GLuint screen_width,
            GLuint screen_height,
            GLuint x,
            GLuint y,
            GLuint text_size,
            GLuint font_size,
            const char* text_char,
            const char* char_font_texture_file_format)
    {
        printText2D(screen_width, screen_height, x, y, text_size, font_size, text_char, char_font_texture_file_format, "left", "bottom");
    }

    void Font2D::set_name(std::string name)
    {
        ontology::set_name(name, this);
    }
}
<commit_msg>Bugfix `Font2D::Font2D`: initialize class members (with dummy values).<commit_after>#include "font2D.hpp"
#include "entity_templates.hpp"
#include "code/ylikuutio/loaders/shader_loader.hpp"
#include "code/ylikuutio/loaders/texture_loader.hpp"

// Include GLEW
#ifndef __GL_GLEW_H_INCLUDED
#define __GL_GLEW_H_INCLUDED
#include <GL/glew.h> // GLfloat, GLuint etc.
#endif

// Include GLM
#ifndef __GLM_GLM_HPP_INCLUDED
#define __GLM_GLM_HPP_INCLUDED
#include <glm/glm.hpp> // glm
#endif

#ifndef __GLM_GTC_MATRIX_TRANSFORM_HPP_INCLUDED
#define __GLM_GTC_MATRIX_TRANSFORM_HPP_INCLUDED
#include <glm/gtc/matrix_transform.hpp>
#endif

// Include standard headers
#include <vector>   // std::vector
#include <cstring>  // std::memcmp, std::strcmp, std::strlen, std::strncmp
#include <stdint.h> // uint32_t etc.
#include <string>   // std::string

namespace ontology
{
    class Universe;

    Font2D::Font2D(
            ontology::Universe* universe_pointer,
            GLuint screen_width,
            GLuint screen_height,
            std::string texture_filename,
            std::string font_texture_file_format)
    {
        // constructor.

        // Initialize class members with some dummy values.
        this->vertexbuffer = 0;
        this->uvbuffer = 0;
        this->programID = 0;
        this->vertex_position_in_screenspaceID = 0;
        this->vertexUVID = 0;
        this->Text2DUniformID = 0;
        this->screen_width_uniform_ID = 0;
        this->screen_height_uniform_ID = 0;

        const char* char_font_texture_file_format = font_texture_file_format.c_str();

        // Initialize texture
        if ((std::strcmp(char_font_texture_file_format, "bmp") == 0) || (std::strcmp(char_font_texture_file_format, "BMP") == 0))
        {
            this->texture = loaders::load_BMP_texture(texture_filename);
        }
        else if ((std::strcmp(char_font_texture_file_format, "dds") == 0) || (std::strcmp(char_font_texture_file_format, "DDS") == 0))
        {
            this->texture = loaders::load_DDS_texture(texture_filename);
        }
        else
        {
            printf("Invalid font texture file format: `%s`. Supported font texture file formats: bmp, BMP, dds, DDS.\n", char_font_texture_file_format);
            this->texture = 0;
            return;
        }

        // Initialize VBO
        glGenBuffers(1, &vertexbuffer);
        glGenBuffers(1, &uvbuffer);

        // Initialize Shader
        programID = loaders::load_shaders("TextVertexShader.vertexshader", "TextVertexShader.fragmentshader");

        // Get a handle for our buffers
        vertex_position_in_screenspaceID = glGetAttribLocation(programID, "vertexPosition_screenspace");
        vertexUVID = glGetAttribLocation(programID, "vertexUV");

        // Initialize uniforms' IDs
        Text2DUniformID = glGetUniformLocation(programID, "myTextureSampler");

        // Initialize uniform window width.
        screen_width_uniform_ID = glGetUniformLocation(programID, "screen_width");
        glUniform1i(screen_width_uniform_ID, screen_width);

        // Initialize uniform window height.
        screen_height_uniform_ID = glGetUniformLocation(programID, "screen_height");
        glUniform1i(screen_height_uniform_ID, screen_height);

        this->universe_pointer = universe_pointer;
    }

    Font2D::~Font2D()
    {
        // destructor.

        // Delete buffers
        glDeleteBuffers(1, &vertexbuffer);
        glDeleteBuffers(1, &uvbuffer);

        // Delete texture
        glDeleteTextures(1, &texture);

        // Delete shader
        glDeleteProgram(programID);
    }

    int32_t Font2D::get_number_of_children()
    {
        return -1;
    }

    int32_t Font2D::get_number_of_descendants()
    {
        return -1;
    }

    void Font2D::printText2D(
            GLuint screen_width,
            GLuint screen_height,
            GLuint x,
            GLuint y,
            GLuint text_size,
            GLuint font_size,
            const char* text_char,
            const char* char_font_texture_file_format,
            const char* horizontal_alignment,
            const char* vertical_alignment)
    {
        // If horizontal alignment is `"left"`, each line begins from the same x coordinate.
        // If horizontal alignment is `"left"` and vertical alignment is `"top"`,
        // then there is no need to check the text beforehand for newlines.
        // Otherwise newlines need to be checked beforehand.
        //
        // If horizontal alignment is right, each line ends in the same x coordinate.
        // Newlines need to be checked beforehand.
        uint32_t length = std::strlen(text_char);

        // Count the number of lines.
        uint32_t number_of_lines = 1;

        uint32_t i = 0;

        while (i < length)
        {
            char character = text_char[i++];

            if (character == (char) '\\')
            {
                // OK, this character was backslash, so read the next character.
                character = text_char[i++];

                if (character == 'n')
                {
                    number_of_lines++;
                }
            }
        }

        GLuint current_left_x;
        GLuint current_top_y;

        if (std::strcmp(horizontal_alignment, "left") == 0)
        {
            current_left_x = x;
        }
        else if (std::strcmp(horizontal_alignment, "center") == 0)
        {
            current_left_x = x - 0.5f * length * text_size;
        }
        else if (std::strcmp(horizontal_alignment, "right") == 0)
        {
            current_left_x = x - length * text_size;
        }

        if (std::strcmp(vertical_alignment, "top") == 0)
        {
            current_top_y = y;
        }
        else if (std::strcmp(vertical_alignment, "center") == 0)
        {
            current_top_y = y + 0.5f * number_of_lines * text_size;
        }
        else if (std::strcmp(vertical_alignment, "bottom") == 0)
        {
            current_top_y = y + number_of_lines * text_size;
        }

        // Fill buffers
        std::vector<glm::vec2> vertices;
        std::vector<glm::vec2> UVs;

        i = 0;

        while (i < length)
        {
            // Print to the right side of X (so far there is no check for input length).
            // Print up of Y.
            GLfloat vertex_up_left_x;
            GLfloat vertex_up_left_y;
            GLfloat vertex_up_right_x;
            GLfloat vertex_up_right_y;
            GLfloat vertex_down_left_x;
            GLfloat vertex_down_left_y;
            GLfloat vertex_down_right_x;
            GLfloat vertex_down_right_y;

            char character = text_char[i++];

            if (character == (char) '\\')
            {
                // OK, this character was backslash, so read the next character.
                character = text_char[i++];

                if (character == 'n')
                {
                    // jump to the beginning of the next line.
                    // `"left"` horizontal alignment and `"top"` vertical alignment are assumed.
                    // TODO: implement newline for other horizontal and vertical alignments too!
                    current_left_x = x;
                    current_top_y -= text_size;
                    continue;
                }
            }

            vertex_up_left_x = vertex_down_left_x = current_left_x;
            vertex_up_right_x = vertex_down_right_x = current_left_x + text_size;
            current_left_x += text_size;

            vertex_down_left_y = vertex_down_right_y = current_top_y - text_size;
            vertex_up_left_y = vertex_up_right_y = current_top_y;

            glm::vec2 vertex_up_left = glm::vec2(vertex_up_left_x, vertex_up_left_y);
            glm::vec2 vertex_up_right = glm::vec2(vertex_up_right_x, vertex_up_right_y);
            glm::vec2 vertex_down_left = glm::vec2(vertex_down_left_x, vertex_down_left_y);
            glm::vec2 vertex_down_right = glm::vec2(vertex_down_right_x, vertex_down_right_y);

            vertices.push_back(vertex_up_left);
            vertices.push_back(vertex_down_left);
            vertices.push_back(vertex_up_right);

            vertices.push_back(vertex_down_right);
            vertices.push_back(vertex_up_right);
            vertices.push_back(vertex_down_left);

            float uv_x = (character % font_size) / (GLfloat) font_size;
            float uv_y;

            if ((std::strcmp(char_font_texture_file_format, "dds") == 0) || (std::strcmp(char_font_texture_file_format, "DDS") == 0))
            {
                uv_y = (character / font_size) / (GLfloat) font_size;
            }
            else if ((std::strcmp(char_font_texture_file_format, "bmp") == 0) || (std::strcmp(char_font_texture_file_format, "BMP") == 0))
            {
                // BMP is stored in the file beginning from the bottom line.
                uv_y = 1 - (character / font_size) / (GLfloat) font_size;
            }

            glm::vec2 uv_up_left = glm::vec2(uv_x, uv_y);
            glm::vec2 uv_up_right = glm::vec2(uv_x + (1.0f / (GLfloat) font_size), uv_y);
            glm::vec2 uv_down_right;
            glm::vec2 uv_down_left;

            if ((std::strcmp(char_font_texture_file_format, "dds") == 0) || (std::strcmp(char_font_texture_file_format, "DDS") == 0))
            {
                uv_down_right = glm::vec2(uv_x + (1.0f / (GLfloat) font_size), (uv_y + 1.0f / (GLfloat) font_size));
                uv_down_left = glm::vec2(uv_x, (uv_y + 1.0f / (GLfloat) font_size));
            }
            else if ((std::strcmp(char_font_texture_file_format, "bmp") == 0) || (std::strcmp(char_font_texture_file_format, "BMP") == 0))
            {
                // BMP is stored in the file beginning from the bottom line.
                uv_down_right = glm::vec2(uv_x + (1.0f / (GLfloat) font_size), (uv_y - 1.0f / (GLfloat) font_size));
                uv_down_left = glm::vec2(uv_x, (uv_y - 1.0f / (GLfloat) font_size));
            }
            UVs.push_back(uv_up_left);
            UVs.push_back(uv_down_left);
            UVs.push_back(uv_up_right);

            UVs.push_back(uv_down_right);
            UVs.push_back(uv_up_right);
            UVs.push_back(uv_down_left);
        }

        glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
        glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec2), &vertices[0], GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
        glBufferData(GL_ARRAY_BUFFER, UVs.size() * sizeof(glm::vec2), &UVs[0], GL_STATIC_DRAW);

        // Bind shader
        glUseProgram(programID);

        // Bind texture
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, texture);
        // Set our "myTextureSampler" sampler to user Material Unit 0
        glUniform1i(Text2DUniformID, 0);

        // Set screen width.
        glUniform1i(screen_width_uniform_ID, screen_width);

        // Set screen height.
        glUniform1i(screen_height_uniform_ID, screen_height);

        // 1st attribute buffer : vertices
        glEnableVertexAttribArray(vertex_position_in_screenspaceID);
        glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
        glVertexAttribPointer(vertex_position_in_screenspaceID, 2, GL_FLOAT, GL_FALSE, 0, (void*) 0);

        // 2nd attribute buffer : UVs
        glEnableVertexAttribArray(vertexUVID);
        glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
        glVertexAttribPointer(vertexUVID, 2, GL_FLOAT, GL_FALSE, 0, (void*) 0);

        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

        // Draw call
        glDrawArrays(GL_TRIANGLES, 0, vertices.size());

        glDisable(GL_BLEND);

        glDisableVertexAttribArray(vertex_position_in_screenspaceID);
        glDisableVertexAttribArray(vertexUVID);
    }

    void Font2D::printText2D(PrintingStruct printing_struct)
    {
        if (printing_struct.text.empty())
        {
            printText2D(
                    printing_struct.screen_width,
                    printing_struct.screen_height,
                    printing_struct.x,
                    printing_struct.y,
                    printing_struct.text_size,
                    printing_struct.font_size,
                    printing_struct.text_char,
                    printing_struct.char_font_texture_file_format,
                    printing_struct.horizontal_alignment,
                    printing_struct.vertical_alignment);
        }
        else
        {
            printText2D(
                    printing_struct.screen_width,
                    printing_struct.screen_height,
                    printing_struct.x,
                    printing_struct.y,
                    printing_struct.text_size,
                    printing_struct.font_size,
                    printing_struct.text.c_str(),
                    printing_struct.char_font_texture_file_format,
                    printing_struct.horizontal_alignment,
                    printing_struct.vertical_alignment);
        }
    }

    void Font2D::printText2D(
            GLuint screen_width,
            GLuint screen_height,
            GLuint x,
            GLuint y,
            GLuint text_size,
            GLuint font_size,
            const char* text_char,
            const char* char_font_texture_file_format)
    {
        printText2D(screen_width, screen_height, x, y, text_size, font_size, text_char, char_font_texture_file_format, "left", "bottom");
    }

    void Font2D::set_name(std::string name)
    {
        ontology::set_name(name, this);
    }
}
<|endoftext|>


<commit_before>/*
 * Sampling.cpp
 *
 *  Created on: 17.02.2014
 *      Author: cls
 */

#include "Sampling.h"
#include "../auxiliary/Random.h"

namespace NetworKit {

node Sampling::randomNode(const Graph& G) {
	assert (G.numberOfNodes() > 0);
	node v = none;
	do {
		v = Aux::Random::integer(G.upperNodeIdBound());
	} while (!G.hasNode(v));
	return v;
}

std::pair<node, node> Sampling::randomEdge(const Graph& G) {
	// TODO:
}

node Sampling::randomNeighbor(const Graph& G, node u) {
	// TODO:
}

} /* namespace NetworKit */

<commit_msg>comment implementation of non-implemented methods to create linker error upon use and silence warnings<commit_after>/*
 * Sampling.cpp
 *
 *  Created on: 17.02.2014
 *      Author: cls
 */

#include "Sampling.h"
#include "../auxiliary/Random.h"

namespace NetworKit {

node Sampling::randomNode(const Graph& G) {
	assert (G.numberOfNodes() > 0);
	node v = none;
	do {
		v = Aux::Random::integer(G.upperNodeIdBound());
	} while (!G.hasNode(v));
	return v;
}

// the following methdods are commented in order to create linker-errors should they be used before
// they are actually defined (not returning from a function with a returntype != void is UB):

//std::pair<node, node> Sampling::randomEdge(const Graph& G) {
//	// TODO: implement
//}

//node Sampling::randomNeighbor(const Graph& G, node u) {
//	// TODO: implement
//}

} /* namespace NetworKit */

<|endoftext|>


<commit_before>#include "base/basictypes.h"
#include "base/logging.h"
#include "base/timeutil.h"

// For NV time functions. Ugly!
#include "gfx_es2/gl_state.h"

#ifdef _WIN32
#include <windows.h>
#else
#include <sys/time.h>
#include <unistd.h>
#endif
#include <stdio.h>

static double curtime = 0;
static float curtime_f = 0;

#ifdef _WIN32

LARGE_INTEGER frequency;
double frequencyMult;
LARGE_INTEGER startTime;

double real_time_now() {
	if (frequency.QuadPart == 0) {
		QueryPerformanceFrequency(&frequency);
		QueryPerformanceCounter(&startTime);
		curtime = 0.0;
		frequencyMult = 1.0 / static_cast<double>(frequency.QuadPart);
	}
	LARGE_INTEGER time;
	QueryPerformanceCounter(&time);
	double elapsed = static_cast<double>(time.QuadPart - startTime.QuadPart);
	return elapsed * frequencyMult;
}

#elif defined(BLACKBERRY)
double real_time_now() {
	struct timespec time;
	clock_gettime(CLOCK_MONOTONIC, &time); // Linux must use CLOCK_MONOTONIC_RAW due to time warps
	return time.tv_sec + time.tv_nsec / 1.0e9;
}
#else

uint64_t _frequency = 0;
uint64_t _starttime = 0;

double real_time_now() {
#ifdef ANDROID
	if (false && gl_extensions.EGL_NV_system_time) {
		// This is needed to profile using PerfHUD on Tegra
		if (_frequency == 0) {
			_frequency = eglGetSystemTimeFrequencyNV();
			_starttime = eglGetSystemTimeNV();
		}

		uint64_t cur = eglGetSystemTimeNV();
		int64_t diff = cur - _starttime;

		return (double)diff / (double)_frequency;
	}
	struct timespec time;
	clock_gettime(CLOCK_MONOTONIC_RAW, &time);
	return time.tv_sec + time.tv_nsec / 1.0e9;
#else
	static time_t start;
	struct timeval tv;
	gettimeofday(&tv, NULL);
	if (start == 0) {
		start = tv.tv_sec;
	}
	tv.tv_sec -= start;
	return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
#endif
}

#endif

void time_update() {
	curtime = real_time_now();
	curtime_f = (float)curtime;

	//printf("curtime: %f %f\n", curtime, curtime_f);
	// also smooth time.
	//curtime+=float((double) (time-_starttime) / (double) _frequency);
	//curtime*=0.5f;
	//curtime+=1.0f/60.0f;
	//lastTime=curtime;
	//curtime_f = (float)curtime;
}

float time_now() {
	return curtime_f;
}

double time_now_d() {
	return curtime;
}

int time_now_ms() {
	return int(curtime*1000.0);
}

void sleep_ms(int ms) {
#ifdef _WIN32
#ifndef METRO
	Sleep(ms);
#endif
#else
	usleep(ms * 1000);
#endif
}

LoggingDeadline::LoggingDeadline(const char *name, int ms) : name_(name), endCalled_(false) {
	totalTime_ = (double)ms * 0.001;
	time_update();
	endTime_ = time_now_d() + totalTime_;
}

LoggingDeadline::~LoggingDeadline() {
	if (!endCalled_)
		End();
}

bool LoggingDeadline::End() {
	endCalled_ = true;
	time_update();
	if (time_now_d() > endTime_) {
		double late = (time_now_d() - endTime_);
		double totalTime = late + totalTime_;
		ELOG("===== %0.2fms DEADLINE PASSED FOR %s at %0.2fms - %0.2fms late =====", totalTime_ * 1000.0, name_, 1000.0 * totalTime, 1000.0 * late);
		return false;
	}
	return true;
}

<commit_msg>Don't use CLOCK_MONOTONIC_RAW on android, it is super choppy on Nexus 9.<commit_after>#include "base/basictypes.h"
#include "base/logging.h"
#include "base/timeutil.h"

// For NV time functions. Ugly!
#include "gfx_es2/gl_state.h"

#ifdef _WIN32
#include <windows.h>
#else
#include <sys/time.h>
#include <unistd.h>
#endif
#include <stdio.h>

static double curtime = 0;
static float curtime_f = 0;

#ifdef _WIN32

LARGE_INTEGER frequency;
double frequencyMult;
LARGE_INTEGER startTime;

double real_time_now() {
	if (frequency.QuadPart == 0) {
		QueryPerformanceFrequency(&frequency);
		QueryPerformanceCounter(&startTime);
		curtime = 0.0;
		frequencyMult = 1.0 / static_cast<double>(frequency.QuadPart);
	}
	LARGE_INTEGER time;
	QueryPerformanceCounter(&time);
	double elapsed = static_cast<double>(time.QuadPart - startTime.QuadPart);
	return elapsed * frequencyMult;
}

#elif defined(BLACKBERRY)
double real_time_now() {
	struct timespec time;
	clock_gettime(CLOCK_MONOTONIC, &time); // Linux must use CLOCK_MONOTONIC_RAW due to time warps
	return time.tv_sec + time.tv_nsec / 1.0e9;
}
#else

uint64_t _frequency = 0;
uint64_t _starttime = 0;

double real_time_now() {
#ifdef ANDROID
	if (false && gl_extensions.EGL_NV_system_time) {
		// This is needed to profile using PerfHUD on Tegra
		if (_frequency == 0) {
			_frequency = eglGetSystemTimeFrequencyNV();
			_starttime = eglGetSystemTimeNV();
		}

		uint64_t cur = eglGetSystemTimeNV();
		int64_t diff = cur - _starttime;

		return (double)diff / (double)_frequency;
	}
#if 0
	// This clock is really "choppy" on Nexus 9!
	struct timespec time;
	clock_gettime(CLOCK_MONOTONIC_RAW, &time);
	return time.tv_sec + time.tv_nsec / 1.0e9;
#else
	static time_t start;
	struct timeval tv;
	gettimeofday(&tv, NULL);
	if (start == 0) {
		start = tv.tv_sec;
	}
	tv.tv_sec -= start;
	return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
#endif

#else
	static time_t start;
	struct timeval tv;
	gettimeofday(&tv, NULL);
	if (start == 0) {
		start = tv.tv_sec;
	}
	tv.tv_sec -= start;
	return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
#endif
}

#endif

void time_update() {
	curtime = real_time_now();
	curtime_f = (float)curtime;

	//printf("curtime: %f %f\n", curtime, curtime_f);
	// also smooth time.
	//curtime+=float((double) (time-_starttime) / (double) _frequency);
	//curtime*=0.5f;
	//curtime+=1.0f/60.0f;
	//lastTime=curtime;
	//curtime_f = (float)curtime;
}

float time_now() {
	return curtime_f;
}

double time_now_d() {
	return curtime;
}

int time_now_ms() {
	return int(curtime*1000.0);
}

void sleep_ms(int ms) {
#ifdef _WIN32
#ifndef METRO
	Sleep(ms);
#endif
#else
	usleep(ms * 1000);
#endif
}

LoggingDeadline::LoggingDeadline(const char *name, int ms) : name_(name), endCalled_(false) {
	totalTime_ = (double)ms * 0.001;
	time_update();
	endTime_ = time_now_d() + totalTime_;
}

LoggingDeadline::~LoggingDeadline() {
	if (!endCalled_)
		End();
}

bool LoggingDeadline::End() {
	endCalled_ = true;
	time_update();
	if (time_now_d() > endTime_) {
		double late = (time_now_d() - endTime_);
		double totalTime = late + totalTime_;
		ELOG("===== %0.2fms DEADLINE PASSED FOR %s at %0.2fms - %0.2fms late =====", totalTime_ * 1000.0, name_, 1000.0 * totalTime, 1000.0 * late);
		return false;
	}
	return true;
}

<|endoftext|>


<commit_before><commit_msg>Bugfix: add missing `#include` line.<commit_after><|endoftext|>


<commit_before><commit_msg>`void Object::bind_to_parent`: refactoring the code.<commit_after><|endoftext|>


<commit_before>#include <primitives/executor.h>

#include <iostream>
#include <string>

#ifdef _WIN32
#include <windows.h>
#endif

//#include "log.h"
//DECLARE_STATIC_LOGGER(logger, "executor");

size_t get_max_threads(size_t N)
{
    return std::max<size_t>(N, std::thread::hardware_concurrency());
}

Executor::Executor(const std::string &name, size_t nThreads)
    : Executor(nThreads, name)
{
}

Executor::Executor(size_t nThreads, const std::string &name)
    : nThreads(nThreads)
{
    thread_pool.resize(nThreads);
    for (size_t i = 0; i < nThreads; i++)
    {
        thread_pool[i].t = std::move(std::thread([this, i, name = name]() mutable
        {
            name += " " + std::to_string(i);
            set_thread_name(name, i);
            run(i);
        }));
    }
}

Executor::~Executor()
{
    stop();
    for (auto &t : thread_pool)
        t.t.join();
}

void Executor::run(size_t i)
{
    while (!done)
    {
        std::string error;
        try
        {
            Task t;
            const size_t spin_count = nThreads * 4;
            for (auto n = 0; n != spin_count; ++n)
            {
                if (thread_pool[(i + n) % nThreads].q.try_pop(t))
                    break;
            }

            // no task popped, probably shutdown command was issues
            if (!t && !thread_pool[i].q.pop(t))
                break;

            thread_pool[i].busy = true;
            t();
        }
        catch (const std::exception &e)
        {
            error = e.what();
            thread_pool[i].eptr = std::current_exception();
        }
        catch (...)
        {
            error = "unknown exception";
            thread_pool[i].eptr = std::current_exception();
        }
        thread_pool[i].busy = false;

        if (!error.empty())
        {
            if (throw_exceptions)
                done = true;
            else
                std::cerr << "executor: " << this << ", thread #" << i + 1 << ", error: " << error << "\n";
                //LOG_ERROR(logger, "executor: " << this << ", thread #" << i + 1 << ", error: " << error);
        }
    }
}

void Executor::stop()
{
    done = true;
    for (auto &t : thread_pool)
        t.q.done();
}

void Executor::wait()
{
    // wait for empty queues
    for (auto &t : thread_pool)
        while (!t.q.empty() && !done)
            std::this_thread::sleep_for(std::chrono::milliseconds(100));

    // wait for end of execution
    for (auto &t : thread_pool)
        while (t.busy && !done)
            std::this_thread::sleep_for(std::chrono::milliseconds(100));

    if (throw_exceptions)
        for (auto &t : thread_pool)
            if (t.eptr)
                std::rethrow_exception(t.eptr);
}

void Executor::set_thread_name(const std::string &name, size_t i) const
{
    if (name.empty())
        return;

#if defined(_MSC_VER)
    constexpr DWORD MS_VC_EXCEPTION = 0x406D1388;

#pragma pack(push, 8)
    struct THREADNAME_INFO
    {
        DWORD dwType;     // Must be 0x1000.
        LPCSTR szName;    // Pointer to thread name
        DWORD dwThreadId; // Thread ID (-1 == current thread)
        DWORD dwFlags;    // Reserved.  Do not use.
    };
#pragma pack(pop)

    THREADNAME_INFO info;
    info.dwType = 0x1000;
    info.szName = name.c_str();
    info.dwThreadId = *(DWORD *)&std::this_thread::get_id();
    info.dwFlags = 0;

    __try
    {
        ::RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info);
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
    }
#endif
}
<commit_msg>Simplify set_thread_name().<commit_after>#include <primitives/executor.h>

#include <iostream>
#include <string>

#ifdef _WIN32
#include <windows.h>
#endif

//#include "log.h"
//DECLARE_STATIC_LOGGER(logger, "executor");

size_t get_max_threads(size_t N)
{
    return std::max<size_t>(N, std::thread::hardware_concurrency());
}

Executor::Executor(const std::string &name, size_t nThreads)
    : Executor(nThreads, name)
{
}

Executor::Executor(size_t nThreads, const std::string &name)
    : nThreads(nThreads)
{
    thread_pool.resize(nThreads);
    for (size_t i = 0; i < nThreads; i++)
    {
        thread_pool[i].t = std::move(std::thread([this, i, name = name]() mutable
        {
            name += " " + std::to_string(i);
            set_thread_name(name, i);
            run(i);
        }));
    }
}

Executor::~Executor()
{
    stop();
    for (auto &t : thread_pool)
        t.t.join();
}

void Executor::run(size_t i)
{
    while (!done)
    {
        std::string error;
        try
        {
            Task t;
            const size_t spin_count = nThreads * 4;
            for (auto n = 0; n != spin_count; ++n)
            {
                if (thread_pool[(i + n) % nThreads].q.try_pop(t))
                    break;
            }

            // no task popped, probably shutdown command was issues
            if (!t && !thread_pool[i].q.pop(t))
                break;

            thread_pool[i].busy = true;
            t();
        }
        catch (const std::exception &e)
        {
            error = e.what();
            thread_pool[i].eptr = std::current_exception();
        }
        catch (...)
        {
            error = "unknown exception";
            thread_pool[i].eptr = std::current_exception();
        }
        thread_pool[i].busy = false;

        if (!error.empty())
        {
            if (throw_exceptions)
                done = true;
            else
                std::cerr << "executor: " << this << ", thread #" << i + 1 << ", error: " << error << "\n";
                //LOG_ERROR(logger, "executor: " << this << ", thread #" << i + 1 << ", error: " << error);
        }
    }
}

void Executor::stop()
{
    done = true;
    for (auto &t : thread_pool)
        t.q.done();
}

void Executor::wait()
{
    // wait for empty queues
    for (auto &t : thread_pool)
        while (!t.q.empty() && !done)
            std::this_thread::sleep_for(std::chrono::milliseconds(100));

    // wait for end of execution
    for (auto &t : thread_pool)
        while (t.busy && !done)
            std::this_thread::sleep_for(std::chrono::milliseconds(100));

    if (throw_exceptions)
        for (auto &t : thread_pool)
            if (t.eptr)
                std::rethrow_exception(t.eptr);
}

void Executor::set_thread_name(const std::string &name, size_t i) const
{
    if (name.empty())
        return;

#if defined(_MSC_VER)
#pragma pack(push, 8)
    struct THREADNAME_INFO
    {
        DWORD dwType = 0x1000;  // Must be 0x1000.
        LPCSTR szName;          // Pointer to thread name
        DWORD dwThreadId = -1;  // Thread ID (-1 == current thread)
        DWORD dwFlags = 0;      // Reserved.  Do not use.
    };
#pragma pack(pop)

    THREADNAME_INFO info;
    info.szName = name.c_str();

    __try
    {
        ::RaiseException(0x406D1388, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info);
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
    }
#endif
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2009 Nokia Corporation.
 *
 * Contact: Marius Vollmer <marius.vollmer@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#include "commandwatcher.h"
#include "sconnect.h"
#include "contextproperty.h"
#include "propertylistener.h"
#include <QTextStream>
#include <QFile>
#include <QSocketNotifier>
#include <QStringList>
#include <QCoreApplication>
#include "contextpropertyinfo.h"
#include <QDebug>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <QMap>

CommandWatcher::CommandWatcher(int commandfd, QMap<QString, ContextProperty*> *properties, QObject *parent) :
    QObject(parent), commandfd(commandfd), properties(properties)
{
    commandNotifier = new QSocketNotifier(commandfd, QSocketNotifier::Read, this);
    sconnect(commandNotifier, SIGNAL(activated(int)), this, SLOT(onActivated()));
    help();
}

void CommandWatcher::onActivated()
{
    // read all available input to commandBuffer
    static QByteArray commandBuffer = "";
    static char buf[1024];
    int readSize;
    fcntl(commandfd, F_SETFL, O_NONBLOCK);
    while ((readSize = read(commandfd, &buf, 1024)) > 0)
        commandBuffer += QByteArray(buf, readSize);

    // handle all available whole input lines as commands
    int nextSeparator;
    while ((nextSeparator = commandBuffer.indexOf('\n')) != -1) {
        // split lines to separate commands by semicolons
        QStringList commands = QString::fromUtf8(commandBuffer.constData()).left(nextSeparator).split(";");
        foreach (QString command, commands)
            interpret(command.trimmed());
        commandBuffer.remove(0, nextSeparator + 1);
    }

    if (readSize == 0) // EOF
        QCoreApplication::exit(0);
}

void CommandWatcher::help()
{
    qDebug() << "Available commands:";
    qDebug() << "  new KEY...                      - create context properties";
    qDebug() << "  delete KEY...                   - delete context properties";
    qDebug() << "  subscribe KEY...                - subscribe to keys";
    qDebug() << "  waitforsubscription KEY...      - subscribe to keys";
    qDebug() << "  unsubscribe KEY...              - unsubscribe from keys";
    qDebug() << "  value KEY [DEF]                 - get value for a key";
    qDebug() << "  key KEY                         - get the key for a key (rather useless)";
    qDebug() << "  ikey KEY                        - get the info()->key for a key (rather useless)";
    qDebug() << "  man KEY                         - get the info()->doc for a key";
    qDebug() << "  type KEY                        - get the info()->type for a key";
    qDebug() << "  plugin KEY                      - get the info()->plugin for a key";
    qDebug() << "  constructionstring KEY          - get the info()->constructionstring for a key";
    qDebug() << "  flush                           - write FLUSHED to stderr and stdout";
    qDebug() << "Any prefix of a command can be used as an abbreviation";
}

void CommandWatcher::interpret(const QString& command) const
{
    QTextStream out(stdout);
    QTextStream err(stderr);
    if (command == "") {
        help();
    } else {
        QStringList args = command.split(" ");
        QString commandName = args[0];
        args.pop_front();

        if (args.size() == 0 && !QString("flush").startsWith(commandName)) {
            help();
            return;
        }

        if (QString("new").startsWith(commandName)) {
            foreach (QString key, args)
                if (properties->contains(key))
                    qDebug() << "key already exists: " << key;
                else {
                    properties->insert(key, new ContextProperty(key, QCoreApplication::instance()));
                    new PropertyListener(properties->value(key));
                }
        } else if (QString("delete").startsWith(commandName)) {
            foreach (QString key, args)
                if (properties->contains(key))
                    delete properties->take(key);
                else
                    qDebug() << "no such key:" << key;
        } else if (QString("subscribe").startsWith(commandName)) {
            foreach (QString key, args)
                if (properties->contains(key))
                    properties->value(key)->subscribe();
                else
                    qDebug() << "no such key:" << key;
        } else if (QString("waitforsubscription").startsWith(commandName)) {
            foreach (QString key, args)
                if (properties->contains(key)) {
                    properties->value(key)->waitForSubscription();
                    out << "wait finished for " << key << endl;
                } else
                    qDebug() << "no such key:" << key;
        } else if (QString("unsubscribe").startsWith(commandName)) {
            foreach (QString key, args)
                if (properties->contains(key))
                    properties->value(key)->unsubscribe();
                else
                    qDebug() << "no such key:" << key;
        } else if (QString("value").startsWith(commandName)) {
            QString key = args[0];
            if (properties->contains(key)) {
                QVariant value;
                if (args.size() > 1) {
                    value = properties->value(key)->value(args[1]);
                } else {
                    value = properties->value(key)->value();
                }
                if (value.isNull())
                    out << "value is Unknown" << endl;
                else
                    out << "value: " << value.typeName() << ":" << value.toString() << endl;
            } else
                qDebug() << "no such key:" << key;
        } else if (QString("key").startsWith(commandName)) {
            QString key = args[0];
            if (properties->contains(key))
                out << "key: " << properties->value(key)->key() << endl;
            else
                qDebug() << "no such key:" << key;
        } else if (QString("ikey").startsWith(commandName)) {
            QString key = args[0];
            if (properties->contains(key))
                out << "ikey: " << properties->value(key)->info()->key() << endl;
            else
                qDebug() << "no such key:" << key;
        } else if (QString("man").startsWith(commandName)) {
            QString key = args[0];
            if (properties->contains(key))
                out << "man: " << properties->value(key)->info()->doc() << endl;
            else
                qDebug() << "no such key:" << key;
        } else if (QString("type").startsWith(commandName)) {
            QString key = args[0];
            if (properties->contains(key))
                out << "type: " << properties->value(key)->info()->type() << endl;
            else
                qDebug() << "no such key:" << key;
        } else if (QString("plugin").startsWith(commandName)) {
            QString key = args[0];
            if (properties->contains(key)) {
                QList<ContextProviderInfo> providers = properties->value(key)->info()->providers();
                if (providers.size() > 0)
                    out << "plugin: " << providers.at(0).plugin;
                else
                    out << "no plugin for key:" << key;
            } else
                qDebug() << "no such key:" << key;
        } else if (QString("constructionstring").startsWith(commandName)) {
            QString key = args[0];
            if (properties->contains(key)) {
                QList<ContextProviderInfo> providers = properties->value(key)->info()->providers();
                if (providers.size() > 0)
                    out << "constructionstring: " << providers.at(0).constructionString;
                else
                    out << "no constructionString for key:" << key;
            } else
                qDebug() << "no such key:" << key;
        } else if (QString("providers").startsWith(commandName)) {
            QString key = args[0];
            if (properties->contains(key)) {
                QList<ContextProviderInfo> providers = properties->value(key)->info()->providers();
                foreach(ContextProviderInfo info, providers)
                    out << "Provider:" << info.plugin << ":" << info.constructionString;
            } else
                qDebug() << "no such key:" << key;
        } else if (QString("flush").startsWith(commandName)) {
            out << "FLUSHED" << endl;
            out.flush();
            err << "FLUSHED" << endl;
            err.flush();
        } else
            help();
    }
}
<commit_msg>context-listen update.<commit_after>/*
 * Copyright (C) 2009 Nokia Corporation.
 *
 * Contact: Marius Vollmer <marius.vollmer@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#include "commandwatcher.h"
#include "sconnect.h"
#include "contextproperty.h"
#include "propertylistener.h"
#include <QTextStream>
#include <QFile>
#include <QSocketNotifier>
#include <QStringList>
#include <QCoreApplication>
#include "contextpropertyinfo.h"
#include <QDebug>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <QMap>

CommandWatcher::CommandWatcher(int commandfd, QMap<QString, ContextProperty*> *properties, QObject *parent) :
    QObject(parent), commandfd(commandfd), properties(properties)
{
    commandNotifier = new QSocketNotifier(commandfd, QSocketNotifier::Read, this);
    sconnect(commandNotifier, SIGNAL(activated(int)), this, SLOT(onActivated()));
    help();
}

void CommandWatcher::onActivated()
{
    // read all available input to commandBuffer
    static QByteArray commandBuffer = "";
    static char buf[1024];
    int readSize;
    fcntl(commandfd, F_SETFL, O_NONBLOCK);
    while ((readSize = read(commandfd, &buf, 1024)) > 0)
        commandBuffer += QByteArray(buf, readSize);

    // handle all available whole input lines as commands
    int nextSeparator;
    while ((nextSeparator = commandBuffer.indexOf('\n')) != -1) {
        // split lines to separate commands by semicolons
        QStringList commands = QString::fromUtf8(commandBuffer.constData()).left(nextSeparator).split(";");
        foreach (QString command, commands)
            interpret(command.trimmed());
        commandBuffer.remove(0, nextSeparator + 1);
    }

    if (readSize == 0) // EOF
        QCoreApplication::exit(0);
}

void CommandWatcher::help()
{
    qDebug() << "Available commands:";
    qDebug() << "  new KEY...                      - create context properties";
    qDebug() << "  delete KEY...                   - delete context properties";
    qDebug() << "  subscribe KEY...                - subscribe to keys";
    qDebug() << "  waitforsubscription KEY...      - subscribe to keys";
    qDebug() << "  unsubscribe KEY...              - unsubscribe from keys";
    qDebug() << "  value KEY [DEF]                 - get value for a key";
    qDebug() << "  key KEY                         - get the key for a key (rather useless)";
    qDebug() << "  ikey KEY                        - get the info()->key for a key (rather useless)";
    qDebug() << "  man KEY                         - get the info()->doc for a key";
    qDebug() << "  type KEY                        - get the info()->type for a key";
    qDebug() << "  plugin KEY                      - get the info()->plugin for a key";
    qDebug() << "  constructionstring KEY          - get the info()->constructionstring for a key";
    qDebug() << "  flush                           - write FLUSHED to stderr and stdout";
    qDebug() << "Any prefix of a command can be used as an abbreviation";
}

void CommandWatcher::interpret(const QString& command) const
{
    QTextStream out(stdout);
    QTextStream err(stderr);
    if (command == "") {
        help();
    } else {
        QStringList args = command.split(" ");
        QString commandName = args[0];
        args.pop_front();

        if (args.size() == 0 && !QString("flush").startsWith(commandName)) {
            help();
            return;
        }

        if (QString("new").startsWith(commandName)) {
            foreach (QString key, args)
                if (properties->contains(key))
                    qDebug() << "key already exists: " << key;
                else {
                    properties->insert(key, new ContextProperty(key, QCoreApplication::instance()));
                    new PropertyListener(properties->value(key));
                }
        } else if (QString("delete").startsWith(commandName)) {
            foreach (QString key, args)
                if (properties->contains(key))
                    delete properties->take(key);
                else
                    qDebug() << "no such key:" << key;
        } else if (QString("subscribe").startsWith(commandName)) {
            foreach (QString key, args)
                if (properties->contains(key))
                    properties->value(key)->subscribe();
                else
                    qDebug() << "no such key:" << key;
        } else if (QString("waitforsubscription").startsWith(commandName)) {
            foreach (QString key, args)
                if (properties->contains(key)) {
                    properties->value(key)->waitForSubscription();
                    out << "wait finished for " << key << endl;
                } else
                    qDebug() << "no such key:" << key;
        } else if (QString("unsubscribe").startsWith(commandName)) {
            foreach (QString key, args)
                if (properties->contains(key))
                    properties->value(key)->unsubscribe();
                else
                    qDebug() << "no such key:" << key;
        } else if (QString("value").startsWith(commandName)) {
            QString key = args[0];
            if (properties->contains(key)) {
                QVariant value;
                if (args.size() > 1) {
                    value = properties->value(key)->value(args[1]);
                } else {
                    value = properties->value(key)->value();
                }
                if (value.isNull())
                    out << "value is Unknown" << endl;
                else
                    out << "value: " << value.typeName() << ":" << value.toString() << endl;
            } else
                qDebug() << "no such key:" << key;
        } else if (QString("key").startsWith(commandName)) {
            QString key = args[0];
            if (properties->contains(key))
                out << "key: " << properties->value(key)->key() << endl;
            else
                qDebug() << "no such key:" << key;
        } else if (QString("ikey").startsWith(commandName)) {
            QString key = args[0];
            if (properties->contains(key))
                out << "ikey: " << properties->value(key)->info()->key() << endl;
            else
                qDebug() << "no such key:" << key;
        } else if (QString("man").startsWith(commandName)) {
            QString key = args[0];
            if (properties->contains(key))
                out << "man: " << properties->value(key)->info()->doc() << endl;
            else
                qDebug() << "no such key:" << key;
        } else if (QString("type").startsWith(commandName)) {
            QString key = args[0];
            if (properties->contains(key))
                out << "type: " << properties->value(key)->info()->type() << endl;
            else
                qDebug() << "no such key:" << key;
        } else if (QString("plugin").startsWith(commandName)) {
            QString key = args[0];
            if (properties->contains(key)) {
                QList<ContextProviderInfo> providers = properties->value(key)->info()->providers();
                if (providers.size() > 0)
                    out << "plugin: " << providers.at(0).plugin << endl;
                else
                    out << "no plugin for key:" << key << endl;
            } else
                qDebug() << "no such key:" << key;
        } else if (QString("constructionstring").startsWith(commandName)) {
            QString key = args[0];
            if (properties->contains(key)) {
                QList<ContextProviderInfo> providers = properties->value(key)->info()->providers();
                if (providers.size() > 0)
                    out << "constructionstring: " << providers.at(0).constructionString << endl;
                else
                    out << "no constructionString for key:" << key << endl;
            } else
                qDebug() << "no such key:" << key;
        } else if (QString("providers").startsWith(commandName)) {
            QString key = args[0];
            if (properties->contains(key)) {
                QList<ContextProviderInfo> providers = properties->value(key)->info()->providers();
                foreach(ContextProviderInfo info, providers)
                    out << "Provider:" << info.plugin << ":" << info.constructionString << endl;
            } else
                qDebug() << "no such key:" << key;
        } else if (QString("flush").startsWith(commandName)) {
            out << "FLUSHED" << endl;
            out.flush();
            err << "FLUSHED" << endl;
            err.flush();
        } else
            help();
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/process_util.h"

#include <ctype.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include <string>

#include "base/eintr_wrapper.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"

namespace {

enum ParsingState {
  KEY_NAME,
  KEY_VALUE
};

// Reads /proc/<pid>/stat and populates |proc_stats| with the values split by
// spaces.
void GetProcStats(pid_t pid, std::vector<std::string>* proc_stats) {
  FilePath stat_file("/proc");
  stat_file = stat_file.Append(IntToString(pid));
  stat_file = stat_file.Append("stat");
  std::string mem_stats;
  if (!file_util::ReadFileToString(stat_file, &mem_stats))
    return;
  SplitString(mem_stats, ' ', proc_stats);
}

}  // namespace

namespace base {

ProcessId GetParentProcessId(ProcessHandle process) {
  FilePath stat_file("/proc");
  stat_file = stat_file.Append(IntToString(process));
  stat_file = stat_file.Append("status");
  std::string status;
  if (!file_util::ReadFileToString(stat_file, &status))
    return -1;

  StringTokenizer tokenizer(status, ":\n");
  ParsingState state = KEY_NAME;
  std::string last_key_name;
  while (tokenizer.GetNext()) {
    switch (state) {
      case KEY_NAME:
        last_key_name = tokenizer.token();
        state = KEY_VALUE;
        break;
      case KEY_VALUE:
        DCHECK(!last_key_name.empty());
        if (last_key_name == "PPid") {
          pid_t ppid = StringToInt(tokenizer.token());
          return ppid;
        }
        state = KEY_NAME;
        break;
    }
  }
  NOTREACHED();
  return -1;
}

FilePath GetProcessExecutablePath(ProcessHandle process) {
  FilePath stat_file("/proc");
  stat_file = stat_file.Append(IntToString(process));
  stat_file = stat_file.Append("exe");
  char exename[2048];
  ssize_t len = readlink(stat_file.value().c_str(), exename, sizeof(exename));
  if (len < 1) {
    // No such process.  Happens frequently in e.g. TerminateAllChromeProcesses
    return FilePath();
  }
  return FilePath(std::string(exename, len));
}

bool LaunchApp(const std::vector<std::string>& argv,
               const environment_vector& environ,
               const file_handle_mapping_vector& fds_to_remap,
               bool wait, ProcessHandle* process_handle) {
  pid_t pid = fork();
  if (pid < 0)
    return false;

  if (pid == 0) {
    // Child process
    InjectiveMultimap fd_shuffle;
    for (file_handle_mapping_vector::const_iterator
        it = fds_to_remap.begin(); it != fds_to_remap.end(); ++it) {
      fd_shuffle.push_back(InjectionArc(it->first, it->second, false));
    }

    for (environment_vector::const_iterator it = environ.begin();
         it != environ.end(); ++it) {
      if (it->first) {
        if (it->second) {
          setenv(it->first, it->second, 1);
        } else {
          unsetenv(it->first);
        }
      }
    }

    if (!ShuffleFileDescriptors(fd_shuffle))
      exit(127);

    // If we are using the SUID sandbox, it sets a magic environment variable
    // ("SBX_D"), so we remove that variable from the environment here on the
    // off chance that it's already set.
    unsetenv("SBX_D");

    CloseSuperfluousFds(fd_shuffle);

    scoped_array<char*> argv_cstr(new char*[argv.size() + 1]);
    for (size_t i = 0; i < argv.size(); i++)
      argv_cstr[i] = const_cast<char*>(argv[i].c_str());
    argv_cstr[argv.size()] = NULL;
    execvp(argv_cstr[0], argv_cstr.get());
    LOG(ERROR) << "LaunchApp: exec failed!, argv_cstr[0] " << argv_cstr[0]
        << ", errno " << errno;
    exit(127);
  } else {
    // Parent process
    if (wait)
      HANDLE_EINTR(waitpid(pid, 0, 0));

    if (process_handle)
      *process_handle = pid;
  }

  return true;
}

bool LaunchApp(const std::vector<std::string>& argv,
               const file_handle_mapping_vector& fds_to_remap,
               bool wait, ProcessHandle* process_handle) {
  base::environment_vector no_env;
  return LaunchApp(argv, no_env, fds_to_remap, wait, process_handle);
}

bool LaunchApp(const CommandLine& cl,
               bool wait, bool start_hidden,
               ProcessHandle* process_handle) {
  file_handle_mapping_vector no_files;
  return LaunchApp(cl.argv(), no_files, wait, process_handle);
}

NamedProcessIterator::NamedProcessIterator(const std::wstring& executable_name,
                                           const ProcessFilter* filter)
    : executable_name_(executable_name), filter_(filter) {
  procfs_dir_ = opendir("/proc");
}

NamedProcessIterator::~NamedProcessIterator() {
  if (procfs_dir_) {
    closedir(procfs_dir_);
    procfs_dir_ = NULL;
  }
}

const ProcessEntry* NamedProcessIterator::NextProcessEntry() {
  bool result = false;
  do {
    result = CheckForNextProcess();
  } while (result && !IncludeEntry());

  if (result)
    return &entry_;

  return NULL;
}

bool NamedProcessIterator::CheckForNextProcess() {
  // TODO(port): skip processes owned by different UID

  dirent* slot = 0;
  const char* openparen;
  const char* closeparen;

  // Arbitrarily guess that there will never be more than 200 non-process
  // files in /proc.  Hardy has 53.
  int skipped = 0;
  const int kSkipLimit = 200;
  while (skipped < kSkipLimit) {
    slot = readdir(procfs_dir_);
    // all done looking through /proc?
    if (!slot)
      return false;

    // If not a process, keep looking for one.
    bool notprocess = false;
    int i;
    for (i = 0; i < NAME_MAX && slot->d_name[i]; ++i) {
       if (!isdigit(slot->d_name[i])) {
         notprocess = true;
         break;
       }
    }
    if (i == NAME_MAX || notprocess) {
      skipped++;
      continue;
    }

    // Read the process's status.
    char buf[NAME_MAX + 12];
    sprintf(buf, "/proc/%s/stat", slot->d_name);
    FILE *fp = fopen(buf, "r");
    if (!fp)
      return false;
    const char* result = fgets(buf, sizeof(buf), fp);
    fclose(fp);
    if (!result)
      return false;

    // Parse the status.  It is formatted like this:
    // %d (%s) %c %d ...
    // pid (name) runstate ppid
    // To avoid being fooled by names containing a closing paren, scan
    // backwards.
    openparen = strchr(buf, '(');
    closeparen = strrchr(buf, ')');
    if (!openparen || !closeparen)
      return false;
    char runstate = closeparen[2];

    // Is the process in 'Zombie' state, i.e. dead but waiting to be reaped?
    // Allowed values: D R S T Z
    if (runstate != 'Z')
      break;

    // Nope, it's a zombie; somebody isn't cleaning up after their children.
    // (e.g. WaitForProcessesToExit doesn't clean up after dead children yet.)
    // There could be a lot of zombies, can't really decrement i here.
  }
  if (skipped >= kSkipLimit) {
    NOTREACHED();
    return false;
  }

  entry_.pid = atoi(slot->d_name);
  entry_.ppid = atoi(closeparen + 3);

  // TODO(port): read pid's commandline's $0, like killall does.  Using the
  // short name between openparen and closeparen won't work for long names!
  int len = closeparen - openparen - 1;
  if (len > NAME_MAX)
    len = NAME_MAX;
  memcpy(entry_.szExeFile, openparen + 1, len);
  entry_.szExeFile[len] = 0;

  return true;
}

bool NamedProcessIterator::IncludeEntry() {
  // TODO(port): make this also work for non-ASCII filenames
  if (WideToASCII(executable_name_) != entry_.szExeFile)
    return false;
  if (!filter_)
    return true;
  return filter_->Includes(entry_.pid, entry_.ppid);
}

// On linux, we return vsize.
size_t ProcessMetrics::GetPagefileUsage() const {
  std::vector<std::string> proc_stats;
  GetProcStats(process_, &proc_stats);
  const size_t kVmSize = 22;
  if (proc_stats.size() > kVmSize)
    return static_cast<size_t>(StringToInt(proc_stats[kVmSize]));
  return 0;
}

size_t ProcessMetrics::GetPeakPagefileUsage() const {
  // http://crbug.com/16251
  return 0;
}

// On linux, we return RSS.
size_t ProcessMetrics::GetWorkingSetSize() const {
  std::vector<std::string> proc_stats;
  GetProcStats(process_, &proc_stats);
  const size_t kVmRss = 23;
  if (proc_stats.size() > kVmRss) {
    size_t num_pages = static_cast<size_t>(StringToInt(proc_stats[kVmRss]));
    return num_pages * getpagesize();
  }
  return 0;
}

size_t ProcessMetrics::GetPeakWorkingSetSize() const {
  // http://crbug.com/16251
  return 0;
}

size_t ProcessMetrics::GetPrivateBytes() const {
  // http://crbug.com/16251
  return 0;
}

bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
  // http://crbug.com/16251
  return false;
}

// To have /proc/self/io file you must enable CONFIG_TASK_IO_ACCOUNTING
// in your kernel configuration.
bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
  std::string proc_io_contents;
  FilePath io_file("/proc");
  io_file = io_file.Append(IntToString(process_));
  io_file = io_file.Append("io");
  if (!file_util::ReadFileToString(io_file, &proc_io_contents))
    return false;

  (*io_counters).OtherOperationCount = 0;
  (*io_counters).OtherTransferCount = 0;

  StringTokenizer tokenizer(proc_io_contents, ": \n");
  ParsingState state = KEY_NAME;
  std::string last_key_name;
  while (tokenizer.GetNext()) {
    switch (state) {
      case KEY_NAME:
        last_key_name = tokenizer.token();
        state = KEY_VALUE;
        break;
      case KEY_VALUE:
        DCHECK(!last_key_name.empty());
        if (last_key_name == "syscr") {
          (*io_counters).ReadOperationCount = StringToInt64(tokenizer.token());
        } else if (last_key_name == "syscw") {
          (*io_counters).WriteOperationCount = StringToInt64(tokenizer.token());
        } else if (last_key_name == "rchar") {
          (*io_counters).ReadTransferCount = StringToInt64(tokenizer.token());
        } else if (last_key_name == "wchar") {
          (*io_counters).WriteTransferCount = StringToInt64(tokenizer.token());
        }
        state = KEY_NAME;
        break;
    }
  }
  return true;
}

}  // namespace base
<commit_msg>This implements the functions necessary for the task manager on Linux.<commit_after>// Copyright (c) 2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/process_util.h"

#include <ctype.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include <string>

#include "base/eintr_wrapper.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/string_tokenizer.h"
#include "base/string_util.h"

namespace {

enum ParsingState {
  KEY_NAME,
  KEY_VALUE
};

// Reads /proc/<pid>/stat and populates |proc_stats| with the values split by
// spaces.
void GetProcStats(pid_t pid, std::vector<std::string>* proc_stats) {
  FilePath stat_file("/proc");
  stat_file = stat_file.Append(IntToString(pid));
  stat_file = stat_file.Append("stat");
  std::string mem_stats;
  if (!file_util::ReadFileToString(stat_file, &mem_stats))
    return;
  SplitString(mem_stats, ' ', proc_stats);
}

}  // namespace

namespace base {

ProcessId GetParentProcessId(ProcessHandle process) {
  FilePath stat_file("/proc");
  stat_file = stat_file.Append(IntToString(process));
  stat_file = stat_file.Append("status");
  std::string status;
  if (!file_util::ReadFileToString(stat_file, &status))
    return -1;

  StringTokenizer tokenizer(status, ":\n");
  ParsingState state = KEY_NAME;
  std::string last_key_name;
  while (tokenizer.GetNext()) {
    switch (state) {
      case KEY_NAME:
        last_key_name = tokenizer.token();
        state = KEY_VALUE;
        break;
      case KEY_VALUE:
        DCHECK(!last_key_name.empty());
        if (last_key_name == "PPid") {
          pid_t ppid = StringToInt(tokenizer.token());
          return ppid;
        }
        state = KEY_NAME;
        break;
    }
  }
  NOTREACHED();
  return -1;
}

FilePath GetProcessExecutablePath(ProcessHandle process) {
  FilePath stat_file("/proc");
  stat_file = stat_file.Append(IntToString(process));
  stat_file = stat_file.Append("exe");
  char exename[2048];
  ssize_t len = readlink(stat_file.value().c_str(), exename, sizeof(exename));
  if (len < 1) {
    // No such process.  Happens frequently in e.g. TerminateAllChromeProcesses
    return FilePath();
  }
  return FilePath(std::string(exename, len));
}

bool LaunchApp(const std::vector<std::string>& argv,
               const environment_vector& environ,
               const file_handle_mapping_vector& fds_to_remap,
               bool wait, ProcessHandle* process_handle) {
  pid_t pid = fork();
  if (pid < 0)
    return false;

  if (pid == 0) {
    // Child process
    InjectiveMultimap fd_shuffle;
    for (file_handle_mapping_vector::const_iterator
        it = fds_to_remap.begin(); it != fds_to_remap.end(); ++it) {
      fd_shuffle.push_back(InjectionArc(it->first, it->second, false));
    }

    for (environment_vector::const_iterator it = environ.begin();
         it != environ.end(); ++it) {
      if (it->first) {
        if (it->second) {
          setenv(it->first, it->second, 1);
        } else {
          unsetenv(it->first);
        }
      }
    }

    if (!ShuffleFileDescriptors(fd_shuffle))
      exit(127);

    // If we are using the SUID sandbox, it sets a magic environment variable
    // ("SBX_D"), so we remove that variable from the environment here on the
    // off chance that it's already set.
    unsetenv("SBX_D");

    CloseSuperfluousFds(fd_shuffle);

    scoped_array<char*> argv_cstr(new char*[argv.size() + 1]);
    for (size_t i = 0; i < argv.size(); i++)
      argv_cstr[i] = const_cast<char*>(argv[i].c_str());
    argv_cstr[argv.size()] = NULL;
    execvp(argv_cstr[0], argv_cstr.get());
    LOG(ERROR) << "LaunchApp: exec failed!, argv_cstr[0] " << argv_cstr[0]
        << ", errno " << errno;
    exit(127);
  } else {
    // Parent process
    if (wait)
      HANDLE_EINTR(waitpid(pid, 0, 0));

    if (process_handle)
      *process_handle = pid;
  }

  return true;
}

bool LaunchApp(const std::vector<std::string>& argv,
               const file_handle_mapping_vector& fds_to_remap,
               bool wait, ProcessHandle* process_handle) {
  base::environment_vector no_env;
  return LaunchApp(argv, no_env, fds_to_remap, wait, process_handle);
}

bool LaunchApp(const CommandLine& cl,
               bool wait, bool start_hidden,
               ProcessHandle* process_handle) {
  file_handle_mapping_vector no_files;
  return LaunchApp(cl.argv(), no_files, wait, process_handle);
}

NamedProcessIterator::NamedProcessIterator(const std::wstring& executable_name,
                                           const ProcessFilter* filter)
    : executable_name_(executable_name), filter_(filter) {
  procfs_dir_ = opendir("/proc");
}

NamedProcessIterator::~NamedProcessIterator() {
  if (procfs_dir_) {
    closedir(procfs_dir_);
    procfs_dir_ = NULL;
  }
}

const ProcessEntry* NamedProcessIterator::NextProcessEntry() {
  bool result = false;
  do {
    result = CheckForNextProcess();
  } while (result && !IncludeEntry());

  if (result)
    return &entry_;

  return NULL;
}

bool NamedProcessIterator::CheckForNextProcess() {
  // TODO(port): skip processes owned by different UID

  dirent* slot = 0;
  const char* openparen;
  const char* closeparen;

  // Arbitrarily guess that there will never be more than 200 non-process
  // files in /proc.  Hardy has 53.
  int skipped = 0;
  const int kSkipLimit = 200;
  while (skipped < kSkipLimit) {
    slot = readdir(procfs_dir_);
    // all done looking through /proc?
    if (!slot)
      return false;

    // If not a process, keep looking for one.
    bool notprocess = false;
    int i;
    for (i = 0; i < NAME_MAX && slot->d_name[i]; ++i) {
       if (!isdigit(slot->d_name[i])) {
         notprocess = true;
         break;
       }
    }
    if (i == NAME_MAX || notprocess) {
      skipped++;
      continue;
    }

    // Read the process's status.
    char buf[NAME_MAX + 12];
    sprintf(buf, "/proc/%s/stat", slot->d_name);
    FILE *fp = fopen(buf, "r");
    if (!fp)
      return false;
    const char* result = fgets(buf, sizeof(buf), fp);
    fclose(fp);
    if (!result)
      return false;

    // Parse the status.  It is formatted like this:
    // %d (%s) %c %d ...
    // pid (name) runstate ppid
    // To avoid being fooled by names containing a closing paren, scan
    // backwards.
    openparen = strchr(buf, '(');
    closeparen = strrchr(buf, ')');
    if (!openparen || !closeparen)
      return false;
    char runstate = closeparen[2];

    // Is the process in 'Zombie' state, i.e. dead but waiting to be reaped?
    // Allowed values: D R S T Z
    if (runstate != 'Z')
      break;

    // Nope, it's a zombie; somebody isn't cleaning up after their children.
    // (e.g. WaitForProcessesToExit doesn't clean up after dead children yet.)
    // There could be a lot of zombies, can't really decrement i here.
  }
  if (skipped >= kSkipLimit) {
    NOTREACHED();
    return false;
  }

  entry_.pid = atoi(slot->d_name);
  entry_.ppid = atoi(closeparen + 3);

  // TODO(port): read pid's commandline's $0, like killall does.  Using the
  // short name between openparen and closeparen won't work for long names!
  int len = closeparen - openparen - 1;
  if (len > NAME_MAX)
    len = NAME_MAX;
  memcpy(entry_.szExeFile, openparen + 1, len);
  entry_.szExeFile[len] = 0;

  return true;
}

bool NamedProcessIterator::IncludeEntry() {
  // TODO(port): make this also work for non-ASCII filenames
  if (WideToASCII(executable_name_) != entry_.szExeFile)
    return false;
  if (!filter_)
    return true;
  return filter_->Includes(entry_.pid, entry_.ppid);
}

// On linux, we return vsize.
size_t ProcessMetrics::GetPagefileUsage() const {
  std::vector<std::string> proc_stats;
  GetProcStats(process_, &proc_stats);
  const size_t kVmSize = 22;
  if (proc_stats.size() > kVmSize)
    return static_cast<size_t>(StringToInt(proc_stats[kVmSize]));
  return 0;
}

// On linux, we return the high water mark of vsize.
size_t ProcessMetrics::GetPeakPagefileUsage() const {
  std::vector<std::string> proc_stats;
  GetProcStats(process_, &proc_stats);
  const size_t kVmPeak = 21;
  if (proc_stats.size() > kVmPeak)
    return static_cast<size_t>(StringToInt(proc_stats[kVmPeak]));
  return 0;
}

// On linux, we return RSS.
size_t ProcessMetrics::GetWorkingSetSize() const {
  std::vector<std::string> proc_stats;
  GetProcStats(process_, &proc_stats);
  const size_t kVmRss = 23;
  if (proc_stats.size() > kVmRss) {
    size_t num_pages = static_cast<size_t>(StringToInt(proc_stats[kVmRss]));
    return num_pages * getpagesize();
  }
  return 0;
}

// On linux, we return the high water mark of RSS.
size_t ProcessMetrics::GetPeakWorkingSetSize() const {
  std::vector<std::string> proc_stats;
  GetProcStats(process_, &proc_stats);
  const size_t kVmHwm = 23;
  if (proc_stats.size() > kVmHwm) {
    size_t num_pages = static_cast<size_t>(StringToInt(proc_stats[kVmHwm]));
    return num_pages * getpagesize();
  }
  return 0;
}

size_t ProcessMetrics::GetPrivateBytes() const {
  // http://crbug.com/16251
  return 0;
}

// Private and Shared working set sizes are obtained from /proc/<pid>/smaps,
// as in http://www.pixelbeat.org/scripts/ps_mem.py
bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
  FilePath stat_file =
    FilePath("/proc").Append(IntToString(process_)).Append("smaps");
  std::string smaps;
  int shared_kb = 0;
  int private_kb = 0;
  int pss_kb = 0;
  bool have_pss = false;
  const int kPssAdjust = 0.5;
  if (!file_util::ReadFileToString(stat_file, &smaps))
    return false;

  StringTokenizer tokenizer(smaps, ":\n");
  ParsingState state = KEY_NAME;
  std::string last_key_name;
  while (tokenizer.GetNext()) {
    switch (state) {
      case KEY_NAME:
        last_key_name = tokenizer.token();
        state = KEY_VALUE;
        break;
      case KEY_VALUE:
        if (last_key_name.empty()) {
          NOTREACHED();
          return false;
        }
        if (StartsWithASCII(last_key_name, "Shared_", 1)) {
            shared_kb += StringToInt(tokenizer.token());
        } else if (StartsWithASCII(last_key_name, "Private_", 1)) {
            private_kb += StringToInt(tokenizer.token());
        } else if (StartsWithASCII(last_key_name, "Pss", 1)) {
            have_pss = true;
            pss_kb += StringToInt(tokenizer.token()) + kPssAdjust;
        }
        state = KEY_NAME;
        break;
    }
  }
  ws_usage->priv = private_kb;
  // Sharable is not calculated, as it does not provide interesting data.
  ws_usage->shareable = 0;
  if (have_pss) {
   ws_usage->shared = pss_kb - private_kb;
  } else {
    ws_usage->shared = shared_kb;
  }
  return true;
}

// To have /proc/self/io file you must enable CONFIG_TASK_IO_ACCOUNTING
// in your kernel configuration.
bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
  std::string proc_io_contents;
  FilePath io_file("/proc");
  io_file = io_file.Append(IntToString(process_));
  io_file = io_file.Append("io");
  if (!file_util::ReadFileToString(io_file, &proc_io_contents))
    return false;

  (*io_counters).OtherOperationCount = 0;
  (*io_counters).OtherTransferCount = 0;

  StringTokenizer tokenizer(proc_io_contents, ": \n");
  ParsingState state = KEY_NAME;
  std::string last_key_name;
  while (tokenizer.GetNext()) {
    switch (state) {
      case KEY_NAME:
        last_key_name = tokenizer.token();
        state = KEY_VALUE;
        break;
      case KEY_VALUE:
        DCHECK(!last_key_name.empty());
        if (last_key_name == "syscr") {
          (*io_counters).ReadOperationCount = StringToInt64(tokenizer.token());
        } else if (last_key_name == "syscw") {
          (*io_counters).WriteOperationCount = StringToInt64(tokenizer.token());
        } else if (last_key_name == "rchar") {
          (*io_counters).ReadTransferCount = StringToInt64(tokenizer.token());
        } else if (last_key_name == "wchar") {
          (*io_counters).WriteTransferCount = StringToInt64(tokenizer.token());
        }
        state = KEY_NAME;
        break;
    }
  }
  return true;
}

}  // namespace base
<|endoftext|>


<commit_before><commit_msg>Convert NOTIMPLs into a bug.<commit_after><|endoftext|>


<commit_before>#include <stan/math/prim/mat.hpp>
#include <gtest/gtest.h>

TEST(MathMatrix, multiply_c_v) {
  stan::math::vector_d v(3);
  v << 1, 2, 3;
  stan::math::vector_d result = stan::math::multiply(2.0, v);
  EXPECT_FLOAT_EQ(2.0, result(0));
  EXPECT_FLOAT_EQ(4.0, result(1));
  EXPECT_FLOAT_EQ(6.0, result(2));
}
TEST(MathMatrix, multiply_c_rv) {
  stan::math::row_vector_d rv(3);
  rv << 1, 2, 3;
  stan::math::row_vector_d result = stan::math::multiply(2.0, rv);
  EXPECT_FLOAT_EQ(2.0, result(0));
  EXPECT_FLOAT_EQ(4.0, result(1));
  EXPECT_FLOAT_EQ(6.0, result(2));
}
TEST(MathMatrix, multiply_c_m) {
  stan::math::matrix_d m(2, 3);
  m << 1, 2, 3, 4, 5, 6;
  stan::math::matrix_d result = stan::math::multiply(2.0, m);
  EXPECT_FLOAT_EQ(2.0, result(0, 0));
  EXPECT_FLOAT_EQ(4.0, result(0, 1));
  EXPECT_FLOAT_EQ(6.0, result(0, 2));
  EXPECT_FLOAT_EQ(8.0, result(1, 0));
  EXPECT_FLOAT_EQ(10.0, result(1, 1));
  EXPECT_FLOAT_EQ(12.0, result(1, 2));
}

TEST(MathMatrix, multiply_rv_v_exception) {
  stan::math::row_vector_d rv;
  stan::math::vector_d v;

  rv.resize(3);
  v.resize(3);
  EXPECT_NO_THROW(stan::math::multiply(rv, v));

  rv.resize(0);
  v.resize(0);
  EXPECT_NO_THROW(stan::math::multiply(rv, v));

  rv.resize(2);
  v.resize(3);
  EXPECT_THROW(stan::math::multiply(rv, v), std::invalid_argument);
}
TEST(MathMatrix, multiply_m_v_exception) {
  stan::math::matrix_d m;
  stan::math::vector_d v;

  m.resize(3, 5);
  v.resize(5);
  EXPECT_NO_THROW(stan::math::multiply(m, v));

  m.resize(3, 0);
  v.resize(0);
  EXPECT_THROW(stan::math::multiply(m, v), std::invalid_argument);

  m.resize(2, 3);
  v.resize(2);
  EXPECT_THROW(stan::math::multiply(m, v), std::invalid_argument);
}
TEST(MathMatrix, multiply_rv_m_exception) {
  stan::math::row_vector_d rv;
  stan::math::matrix_d m;

  rv.resize(3);
  m.resize(3, 5);
  EXPECT_NO_THROW(stan::math::multiply(rv, m));

  rv.resize(0);
  m.resize(0, 3);
  EXPECT_THROW(stan::math::multiply(rv, m), std::invalid_argument);

  rv.resize(3);
  m.resize(2, 3);
  EXPECT_THROW(stan::math::multiply(rv, m), std::invalid_argument);
}
TEST(MathMatrix, multiply_m_m_exception) {
  stan::math::matrix_d m1, m2;

  m1.resize(1, 3);
  m2.resize(3, 5);
  EXPECT_NO_THROW(stan::math::multiply(m1, m2));

  m1.resize(2, 0);
  m2.resize(0, 3);
  EXPECT_THROW(stan::math::multiply(m1, m2), std::invalid_argument);

  m1.resize(4, 3);
  m2.resize(2, 3);
  EXPECT_THROW(stan::math::multiply(m1, m2), std::invalid_argument);
}

TEST(MathMatrix, multiply) {
  stan::math::vector_d v0;
  stan::math::row_vector_d rv0;
  stan::math::matrix_d m0;

  using stan::math::multiply;
  EXPECT_NO_THROW(multiply(v0, 2.0));
  EXPECT_NO_THROW(multiply(rv0, 2.0));
  EXPECT_NO_THROW(multiply(m0, 2.0));
  EXPECT_NO_THROW(multiply(2.0, v0));
  EXPECT_NO_THROW(multiply(2.0, rv0));
  EXPECT_NO_THROW(multiply(2.0, m0));
}

TEST(AgradRevMatrix, multiply_int) {
  using stan::math::assign;
  using stan::math::multiply;

  typedef Eigen::Matrix<double, Eigen::Dynamic, 1> vector_d;

  int d_int = 2;
  vector_d vec(4);
  vec << 1, 2, 3, 4;
  vector_d t_vec(4);
  assign(t_vec, multiply(vec, d_int));
}

TEST(AgradRevMatrix, multiply_vector_int) {
  using stan::math::multiply;
  using stan::math::vector_d;

  vector_d dvec(3);
  dvec << 1, 2, 3;
  int a = 2;
  vector_d prod_vec = multiply(dvec, a);
  EXPECT_EQ(3, prod_vec.size());
  EXPECT_EQ(2.0, prod_vec[0]);
  EXPECT_EQ(4.0, prod_vec[1]);
  EXPECT_EQ(6.0, prod_vec[2]);
}

#ifdef STAN_OPENCL
#define EXPECT_MATRIX_NEAR(A, B, DELTA) \
  for (int i = 0; i < A.size(); i++)    \
    EXPECT_NEAR(A(i), B(i), DELTA);

TEST(MathMatrix, multiply_opencl) {
  int multiply_dim_prod_worth_transfer
      = stan::math::opencl_context.tuning_opts()
            .multiply_dim_prod_worth_transfer;
  stan::math::opencl_context.tuning_opts().multiply_dim_prod_worth_transfer
      = 0;
  using stan::math::multiply;
  int size = 400;
  stan::math::matrix_d m1 = stan::math::matrix_d::Random(size, size).eval();
  stan::math::matrix_d m2 = stan::math::matrix_d::Random(size, size).eval();

  stan::math::matrix_d m3_cl = multiply(m1, m2);
  // to make sure we dont use OpenCL
  stan::math::opencl_context.tuning_opts().multiply_dim_prod_worth_transfer
      = INT_MAX;

  stan::math::matrix_d m3 = multiply(m1, m2);

  EXPECT_MATRIX_NEAR(m3_cl, m3, 1e-10);
  stan::math::opencl_context.tuning_opts().multiply_dim_prod_worth_transfer
      = multiply_dim_prod_worth_transfer;
}
#endif
<commit_msg>[Jenkins] auto-formatting by clang-format version 6.0.0 (tags/google/stable/2017-11-14)<commit_after>#include <stan/math/prim/mat.hpp>
#include <gtest/gtest.h>

TEST(MathMatrix, multiply_c_v) {
  stan::math::vector_d v(3);
  v << 1, 2, 3;
  stan::math::vector_d result = stan::math::multiply(2.0, v);
  EXPECT_FLOAT_EQ(2.0, result(0));
  EXPECT_FLOAT_EQ(4.0, result(1));
  EXPECT_FLOAT_EQ(6.0, result(2));
}
TEST(MathMatrix, multiply_c_rv) {
  stan::math::row_vector_d rv(3);
  rv << 1, 2, 3;
  stan::math::row_vector_d result = stan::math::multiply(2.0, rv);
  EXPECT_FLOAT_EQ(2.0, result(0));
  EXPECT_FLOAT_EQ(4.0, result(1));
  EXPECT_FLOAT_EQ(6.0, result(2));
}
TEST(MathMatrix, multiply_c_m) {
  stan::math::matrix_d m(2, 3);
  m << 1, 2, 3, 4, 5, 6;
  stan::math::matrix_d result = stan::math::multiply(2.0, m);
  EXPECT_FLOAT_EQ(2.0, result(0, 0));
  EXPECT_FLOAT_EQ(4.0, result(0, 1));
  EXPECT_FLOAT_EQ(6.0, result(0, 2));
  EXPECT_FLOAT_EQ(8.0, result(1, 0));
  EXPECT_FLOAT_EQ(10.0, result(1, 1));
  EXPECT_FLOAT_EQ(12.0, result(1, 2));
}

TEST(MathMatrix, multiply_rv_v_exception) {
  stan::math::row_vector_d rv;
  stan::math::vector_d v;

  rv.resize(3);
  v.resize(3);
  EXPECT_NO_THROW(stan::math::multiply(rv, v));

  rv.resize(0);
  v.resize(0);
  EXPECT_NO_THROW(stan::math::multiply(rv, v));

  rv.resize(2);
  v.resize(3);
  EXPECT_THROW(stan::math::multiply(rv, v), std::invalid_argument);
}
TEST(MathMatrix, multiply_m_v_exception) {
  stan::math::matrix_d m;
  stan::math::vector_d v;

  m.resize(3, 5);
  v.resize(5);
  EXPECT_NO_THROW(stan::math::multiply(m, v));

  m.resize(3, 0);
  v.resize(0);
  EXPECT_THROW(stan::math::multiply(m, v), std::invalid_argument);

  m.resize(2, 3);
  v.resize(2);
  EXPECT_THROW(stan::math::multiply(m, v), std::invalid_argument);
}
TEST(MathMatrix, multiply_rv_m_exception) {
  stan::math::row_vector_d rv;
  stan::math::matrix_d m;

  rv.resize(3);
  m.resize(3, 5);
  EXPECT_NO_THROW(stan::math::multiply(rv, m));

  rv.resize(0);
  m.resize(0, 3);
  EXPECT_THROW(stan::math::multiply(rv, m), std::invalid_argument);

  rv.resize(3);
  m.resize(2, 3);
  EXPECT_THROW(stan::math::multiply(rv, m), std::invalid_argument);
}
TEST(MathMatrix, multiply_m_m_exception) {
  stan::math::matrix_d m1, m2;

  m1.resize(1, 3);
  m2.resize(3, 5);
  EXPECT_NO_THROW(stan::math::multiply(m1, m2));

  m1.resize(2, 0);
  m2.resize(0, 3);
  EXPECT_THROW(stan::math::multiply(m1, m2), std::invalid_argument);

  m1.resize(4, 3);
  m2.resize(2, 3);
  EXPECT_THROW(stan::math::multiply(m1, m2), std::invalid_argument);
}

TEST(MathMatrix, multiply) {
  stan::math::vector_d v0;
  stan::math::row_vector_d rv0;
  stan::math::matrix_d m0;

  using stan::math::multiply;
  EXPECT_NO_THROW(multiply(v0, 2.0));
  EXPECT_NO_THROW(multiply(rv0, 2.0));
  EXPECT_NO_THROW(multiply(m0, 2.0));
  EXPECT_NO_THROW(multiply(2.0, v0));
  EXPECT_NO_THROW(multiply(2.0, rv0));
  EXPECT_NO_THROW(multiply(2.0, m0));
}

TEST(AgradRevMatrix, multiply_int) {
  using stan::math::assign;
  using stan::math::multiply;

  typedef Eigen::Matrix<double, Eigen::Dynamic, 1> vector_d;

  int d_int = 2;
  vector_d vec(4);
  vec << 1, 2, 3, 4;
  vector_d t_vec(4);
  assign(t_vec, multiply(vec, d_int));
}

TEST(AgradRevMatrix, multiply_vector_int) {
  using stan::math::multiply;
  using stan::math::vector_d;

  vector_d dvec(3);
  dvec << 1, 2, 3;
  int a = 2;
  vector_d prod_vec = multiply(dvec, a);
  EXPECT_EQ(3, prod_vec.size());
  EXPECT_EQ(2.0, prod_vec[0]);
  EXPECT_EQ(4.0, prod_vec[1]);
  EXPECT_EQ(6.0, prod_vec[2]);
}

#ifdef STAN_OPENCL
#define EXPECT_MATRIX_NEAR(A, B, DELTA) \
  for (int i = 0; i < A.size(); i++)    \
    EXPECT_NEAR(A(i), B(i), DELTA);

TEST(MathMatrix, multiply_opencl) {
  int multiply_dim_prod_worth_transfer
      = stan::math::opencl_context.tuning_opts()
            .multiply_dim_prod_worth_transfer;
  stan::math::opencl_context.tuning_opts().multiply_dim_prod_worth_transfer = 0;
  using stan::math::multiply;
  int size = 400;
  stan::math::matrix_d m1 = stan::math::matrix_d::Random(size, size).eval();
  stan::math::matrix_d m2 = stan::math::matrix_d::Random(size, size).eval();

  stan::math::matrix_d m3_cl = multiply(m1, m2);
  // to make sure we dont use OpenCL
  stan::math::opencl_context.tuning_opts().multiply_dim_prod_worth_transfer
      = INT_MAX;

  stan::math::matrix_d m3 = multiply(m1, m2);

  EXPECT_MATRIX_NEAR(m3_cl, m3, 1e-10);
  stan::math::opencl_context.tuning_opts().multiply_dim_prod_worth_transfer
      = multiply_dim_prod_worth_transfer;
}
#endif
<|endoftext|>


<commit_before>
#include <gloperate/stages/multiframe/MultiFrameAggregationStage.h>

#include <globjects/base/StringTemplate.h>
#include <globjects/base/StaticStringSource.h>
#include <globjects/VertexArray.h>
#include <globjects/VertexAttributeBinding.h>
#include <globjects/Framebuffer.h>
#include <globjects/globjects.h>

#include <glbinding/gl/functions.h>
#include <glbinding/gl/enum.h>

static const std::array<glm::vec2, 4> s_vertices { {
    glm::vec2( +1.f, -1.f ),
    glm::vec2( +1.f, +1.f ),
    glm::vec2( -1.f, -1.f ),
    glm::vec2( -1.f, +1.f ) } };

static const char * s_vertexShader = R"(
    #version 140
    #extension GL_ARB_explicit_attrib_location : require

    layout (location = 0) in vec2 a_vertex;
    out vec2 v_uv;

    void main()
    {
        v_uv = a_vertex * 0.5 + 0.5;
        gl_Position = vec4(a_vertex, 0.0, 1.0);
    }
)";

static const char * s_fragmentShader = R"(
    #version 140
    #extension GL_ARB_explicit_attrib_location : require

    uniform sampler2D tex;

    layout (location = 0) out vec4 fragColor;

    in vec2 v_uv;

    void main()
    {
        fragColor = texture(tex, v_uv);
    }
)";

namespace gloperate
{

CPPEXPOSE_COMPONENT(MultiFrameAggregationStage, gloperate::Stage)

MultiFrameAggregationStage::MultiFrameAggregationStage(Environment * environment, const std::string & name)
: Stage(environment, name)
, aggregationFBO("aggregationFBO", this)
, texture("texture", this)
, textureRerendered("textureRerendered", this)
, viewport("viewport", this)
, aggregationFactor("aggregationFactor", this)
, aggregatedFBO("aggregatedFBO", this)
{
}

MultiFrameAggregationStage::~MultiFrameAggregationStage()
{
}

void MultiFrameAggregationStage::onContextInit(AbstractGLContext * context)
{
    setupGeometry();
    setupProgram();
}

void MultiFrameAggregationStage::onProcess(AbstractGLContext * context)
{
    gl::glViewport(
        (*viewport).x,
        (*viewport).y,
        (*viewport).z,
        (*viewport).w
    );

    globjects::Framebuffer * fbo = *aggregationFBO;
    if (!fbo) fbo = globjects::Framebuffer::defaultFBO();
    fbo->bind(gl::GL_FRAMEBUFFER);

    (*texture)->bindActive(0);
    gl::glBlendColor(0.0f, 0.0f, 0.0f, *aggregationFactor);
    gl::glBlendFunc(gl::GL_CONSTANT_ALPHA, gl::GL_ONE_MINUS_CONSTANT_ALPHA);
    gl::glBlendEquation(gl::GL_FUNC_ADD);
    gl::glEnable(gl::GL_BLEND);
    gl::glDisable(gl::GL_DEPTH_TEST);

    m_program->use();
    m_vao->drawArrays(gl::GL_TRIANGLE_STRIP, 0, 4);
    m_program->release();

    gl::glDisable(gl::GL_BLEND);
    gl::glEnable(gl::GL_DEPTH_TEST);

    aggregatedFBO.setValue(*aggregationFBO);
}

void MultiFrameAggregationStage::setupGeometry()
{
    m_vao = new globjects::VertexArray;
    m_vertexBuffer = new globjects::Buffer();
    m_vertexBuffer->setData(s_vertices, gl::GL_STATIC_DRAW);

    auto binding = m_vao->binding(0);
    binding->setAttribute(0);
    binding->setBuffer(m_vertexBuffer, 0, sizeof(glm::vec2));
    binding->setFormat(2, gl::GL_FLOAT, gl::GL_FALSE, 0);
    m_vao->enable(0);
}

void MultiFrameAggregationStage::setupProgram()
{
    globjects::StringTemplate * vertexShaderSource   = new globjects::StringTemplate(new globjects::StaticStringSource(s_vertexShader  ));
    globjects::StringTemplate * fragmentShaderSource = new globjects::StringTemplate(new globjects::StaticStringSource(s_fragmentShader));

#ifdef __APPLE__
    vertexShaderSource  ->replace("#version 140", "#version 150");
    fragmentShaderSource->replace("#version 140", "#version 150");
#endif

    m_vertexShader   = new globjects::Shader(gl::GL_VERTEX_SHADER,   vertexShaderSource);
    m_fragmentShader = new globjects::Shader(gl::GL_FRAGMENT_SHADER, fragmentShaderSource);
    m_program = new globjects::Program();
    m_program->attach(m_vertexShader, m_fragmentShader);

    m_program->setUniform("tex", 0);
}

} // namespace gloperate
<commit_msg>Fix black bottom & left borders<commit_after>
#include <gloperate/stages/multiframe/MultiFrameAggregationStage.h>

#include <globjects/base/StringTemplate.h>
#include <globjects/base/StaticStringSource.h>
#include <globjects/VertexArray.h>
#include <globjects/VertexAttributeBinding.h>
#include <globjects/Framebuffer.h>
#include <globjects/globjects.h>

#include <glbinding/gl/functions.h>
#include <glbinding/gl/enum.h>

static const std::array<glm::vec2, 4> s_vertices { {
    glm::vec2( +1.f, -1.f ),
    glm::vec2( +1.f, +1.f ),
    glm::vec2( -1.f, -1.f ),
    glm::vec2( -1.f, +1.f ) } };

static const char * s_vertexShader = R"(
    #version 140
    #extension GL_ARB_explicit_attrib_location : require

    layout (location = 0) in vec2 a_vertex;
    out vec2 v_uv;

    void main()
    {
        v_uv = a_vertex * 0.5 + 0.5;
        gl_Position = vec4(a_vertex, 0.0, 1.0);
    }
)";

static const char * s_fragmentShader = R"(
    #version 140
    #extension GL_ARB_explicit_attrib_location : require

    uniform sampler2D tex;

    layout (location = 0) out vec4 fragColor;

    in vec2 v_uv;

    void main()
    {
        fragColor = texture(tex, v_uv);
    }
)";

namespace gloperate
{

CPPEXPOSE_COMPONENT(MultiFrameAggregationStage, gloperate::Stage)

MultiFrameAggregationStage::MultiFrameAggregationStage(Environment * environment, const std::string & name)
: Stage(environment, name)
, aggregationFBO("aggregationFBO", this)
, texture("texture", this)
, textureRerendered("textureRerendered", this)
, viewport("viewport", this)
, aggregationFactor("aggregationFactor", this)
, aggregatedFBO("aggregatedFBO", this)
{
}

MultiFrameAggregationStage::~MultiFrameAggregationStage()
{
}

void MultiFrameAggregationStage::onContextInit(AbstractGLContext * context)
{
    setupGeometry();
    setupProgram();
}

void MultiFrameAggregationStage::onProcess(AbstractGLContext * context)
{
    gl::glViewport(
        0,              // Origin (0,0) because content was already shifted in main render pass
        0,              // Applying the origin again would shift the result again
        (*viewport).z,
        (*viewport).w
    );

    globjects::Framebuffer * fbo = *aggregationFBO;
    if (!fbo) fbo = globjects::Framebuffer::defaultFBO();
    fbo->bind(gl::GL_FRAMEBUFFER);

    (*texture)->bindActive(0);
    gl::glBlendColor(0.0f, 0.0f, 0.0f, *aggregationFactor);
    gl::glBlendFunc(gl::GL_CONSTANT_ALPHA, gl::GL_ONE_MINUS_CONSTANT_ALPHA);
    gl::glBlendEquation(gl::GL_FUNC_ADD);
    gl::glEnable(gl::GL_BLEND);
    gl::glDisable(gl::GL_DEPTH_TEST);

    m_program->use();
    m_vao->drawArrays(gl::GL_TRIANGLE_STRIP, 0, 4);
    m_program->release();

    gl::glDisable(gl::GL_BLEND);
    gl::glEnable(gl::GL_DEPTH_TEST);

    aggregatedFBO.setValue(*aggregationFBO);
}

void MultiFrameAggregationStage::setupGeometry()
{
    m_vao = new globjects::VertexArray;
    m_vertexBuffer = new globjects::Buffer();
    m_vertexBuffer->setData(s_vertices, gl::GL_STATIC_DRAW);

    auto binding = m_vao->binding(0);
    binding->setAttribute(0);
    binding->setBuffer(m_vertexBuffer, 0, sizeof(glm::vec2));
    binding->setFormat(2, gl::GL_FLOAT, gl::GL_FALSE, 0);
    m_vao->enable(0);
}

void MultiFrameAggregationStage::setupProgram()
{
    globjects::StringTemplate * vertexShaderSource   = new globjects::StringTemplate(new globjects::StaticStringSource(s_vertexShader  ));
    globjects::StringTemplate * fragmentShaderSource = new globjects::StringTemplate(new globjects::StaticStringSource(s_fragmentShader));

#ifdef __APPLE__
    vertexShaderSource  ->replace("#version 140", "#version 150");
    fragmentShaderSource->replace("#version 140", "#version 150");
#endif

    m_vertexShader   = new globjects::Shader(gl::GL_VERTEX_SHADER,   vertexShaderSource);
    m_fragmentShader = new globjects::Shader(gl::GL_FRAGMENT_SHADER, fragmentShaderSource);
    m_program = new globjects::Program();
    m_program->attach(m_vertexShader, m_fragmentShader);

    m_program->setUniform("tex", 0);
}

} // namespace gloperate
<|endoftext|>