<commit_before>/***
 * Removes the meta boxes from the provided mpeg4 source file, writing the result
 * out to a new file given the provided filename.
 *
 * This sample program only works for media files that stay within 32-bit box/file sizes.
 * If the file is larger than the 32-bit maximum, the following additions could be made:
 *
 * 1. Check for 64-bit boxes size encoding (atom size=1) and adjust according.
 * 2. Find the co64 table instead of stco table, and modify those table entries.
 */
#include "stdio.h"
#include "stdint.h"
#include "stdlib.h"
#include "stddef.h"
#include "string.h"
#include <vector>

/* M4A atoms can be either data holders, or containers of other
 * atoms. Actually, it's slightly more complicated than that, since there
 * are a few choice atoms that are containers that also have data inside of them.
 * However, we don't need to worry about this in this utility, since the only
 * container that has that property is the "meta" container, but we're just
 * removing it, anyway; we don't need to recurse into it.
 *
 * According to the docs for the m4a file type, we can find meta in the following
 * places in the hierarchy:
 * meta
 * moov.udta.meta
 * moov.udta.trak.meta
 *
 * So, based on that information, we track make sure to check the
 * substructure of the necessary containers.
 */
const char *const containers_of_interest = "moov|udta|trak|mdia|minf|stbl";
typedef struct atom_t {
    atom_t* parent;
    union byte_addressable {
        uint64_t word;
        uint8_t bytes[8];
    } len;
    char name[5];
    uint64_t data_size;
    int64_t data_remaining;
    unsigned char* data;
    bool container;
    std::vector<atom_t*> children;
} atom_t;

/***
 * Find the next box (atom) in the provided m4a file
 *
 * Allocates memory for the atom if necessary, and returns
 * a new atom_t with information about the new atom.
 */
atom_t* get_next_box(FILE* m4a_file) {
    atom_t *atom = (atom_t*)malloc(sizeof(atom_t));
    int i;

    /* Read in big-endian order */

    //atom->len.word = 0;
    //for(i = 3; i >= 0; i--) {
    //    fread(&(atom->len.bytes[i]), 1, 1, m4a_file);
    //}

    fread(atom->name, 1, 4, m4a_file);

    /* If the standard length word is 1, then we
     * expect an 8-byte length immediately follow
     * the name.
     *
     * Also the header is effectively 16 bytes now. */
    if(atom->len.word == 1) {
        /* Read in big-endian order */
        for(i = 7; i >= 0; i--) {
            fread(&(atom->len.bytes[i]), 1, 1, m4a_file);
        }
        atom->data_size = atom->len.word - 16;
    } else {
        atom->data_size = atom->len.word - 8;
    }

    /* Initialize the struct depending on whether
     * it's a container of interest or just a
     * data blob to pass through.
     */
    if(strstr(containers_of_interest, atom->name) != 0) {
        //If it's a container, mark the size in data_remaining so the main loop
        //knows how much to process
        atom->data = NULL;
        atom->data_remaining = atom->data_size;
    } else {
        //Otherwise, just throw the data in a char blob
        //to dump back out later
        atom->data = (unsigned char*)malloc(atom->data_size);;
        fread(atom->data, atom->data_size, 1, m4a_file);
        atom->data_remaining = 0;
    }
    return atom;
}

// A little function to look for meta tags in a less structured way
// Just used for testing
// Could possibly result in a false positive if the "meta" tag appears
// in binary data by chance, although my hunch is that this is unlikely.
int find_meta(FILE *m4a_file) {
    const char* target = "meta";
    unsigned int tmp;
    int i;
    for(i = 0; i < strlen(target); i++) {
        tmp <<= 8;
        tmp |= (unsigned char)target[i];
    }
    const unsigned int target_checksum = tmp; //Sum of characters in "meta"
    int checksum = 0;
    unsigned char c = 0;
    unsigned char buffer[8] = {0,0,0,0,0,0,0,0};
    int index = 0;
    bool found = false;
    while(fread(&c, 1, 1, m4a_file) > 0) {
        index++;
        buffer[index & 7] = c;
        checksum <<= 8;
        checksum |= c;
        if(checksum == target_checksum) {
            found = true;
            for(i = strlen(target)-1; i >=0; i--) {
                if(target[i] != buffer[(index+5+i) & 7]) {
                    found = false;
                    break;
                }
            }
            if(found == true) {
                printf("Found 'meta' at position %lu\n", index - strlen(target));
                return index;
            }
        }
    }
    printf("found no meta box in all %d positions\n",index);
    return -1;
}

void print_tree_rec(atom_t* node, int level) {
    int i;
    for(i=0; i<level; i++) {
        printf(".");
    }

    //skip root content, it's not *really* an atom
    if(node->parent != NULL) {
        printf("%llu %s\n", node->len.word, node->name);
    }
    for(i=0; i<node->children.size(); i++) {
        print_tree_rec(node->children[i], level+1);
    }
}
void print_tree(atom_t* node) {
    print_tree_rec(node, 0);
}

void output_tree(atom_t* node, FILE *out_file) {
    int i;

    //skip root content, it's not *really* an atom
    if(node->parent != NULL) {
        for(i = 3; i >= 0; i--) {
            fwrite(&node->len.bytes[i], 1, 1, out_file);
        }
        fwrite(node->name, 4, 1, out_file);
        if(node->data_size > 0 && node->data != NULL) {
            fwrite(node->data, node->data_size, 1, out_file);
        }
    }

    for(i=0; i < node->children.size(); i++) {
        output_tree(node->children[i], out_file);
    }
}

void adjust_stco_offset(atom_t *stco, int offset_adjust) {
    int i,j;
    //Offset past the version byte
    unsigned char* stco_data_ptr = (stco->data + 4);
    int stco_entries = htonl(*((uint32_t*)(stco_data_ptr)));

    //Ofset version bytes and length bytes
    stco_data_ptr = stco->data + 8;

    //Read the bytes in big-endian order,
    //subtract offset,
    //write back out.
    for(i = 0; i < stco_entries; i++) {
        uint32_t stco_offset = htonl(*((uint32_t*)(stco_data_ptr)));
        stco_offset -= offset_adjust;
        *((uint32_t*)stco_data_ptr) = htonl(stco_offset);
        stco_data_ptr += 4;
    }
}

atom_t* build_tree(FILE* m4a_file) {

    bool visited_mdat = false;

    //Place to hold the current working atom.
    atom_t *atom;

    //Create an abstract root node to hold the top-level
    //atom list.
    atom_t *root = (atom_t*)malloc(sizeof(atom_t));
    root->parent == NULL;
    root->data_remaining = -1;

    atom_t *current_parent = root;

    atom_t *stco = NULL;

    uint64_t chunk_offset_adjust = 0;

    int level = 0;

    /* Loop through the rest of the atoms */
    while((atom = get_next_box(m4a_file))->len.word > 0) {
        int i;
        //Set the parent of the newly created atom
        atom->parent = current_parent;

        //Note whether or not we've visited the mdat box
        //So that we know if stco offsets must be
        //adjusted later.
        if(strncmp(atom->name, "mdat", 4) == 0) {
            visited_mdat = true;
        }

        //If it's a meta box, don't add it to the
        //current atom list, so it's removed from
        //the internal tree structure. Also, iterate
        //back up through the parent pointers adjusting
        //box sizes to account for its removal.
        if(strncmp(atom->name, "meta", 4) == 0) {
            //reset the parent values
            atom_t *cur = atom->parent;
            while(cur != NULL) {
                cur->len.word -= atom->len.word;
                cur = cur->parent;
            }
            //update the chunk offset adjustment
            //but only if this meta chunk is before
            //the mdat box. If it's after,
            //it won't change stco offsets relative
            //to the file start.
            if(visited_mdat == false) {
                chunk_offset_adjust += atom->len.word;
            }
        } else {
            current_parent->children.push_back(atom);
        }

        //If we have a chunk_offset_adjust and
        //the current atom is stco,
        //save it so we can adjust it at the end if necessary.
        if(strncmp(atom->name, "stco", 4) == 0) {
            stco = atom;
        }

        //Subtract size of current atom from
        //the data_remaining of the parent
        //before the next step, which might reset the
        //parent pointer to a new level.
        if(current_parent != root) {
            current_parent->data_remaining -= atom->len.word;
        }

        //If the atom has data_remaining set, then must have some children
        if(atom->data_remaining > 0) {
            current_parent = atom;
            level++;
        }

        //Check if we have data remaining in the parent.
        //If not, if atom was the last one in the parent.
        //So, move back up one level
        //Make sure we haven't overrun any expected sizes in
        //parents further up
        if(current_parent != root) {
            if(current_parent->data_remaining < 0) {
                printf("Something wrong: child atom overruns the parent size.");
                printf("Parent name is: %s\n",current_parent->name);
                exit(0);
            }

            //We're done getting the children of this parent, move back up.
            while (current_parent && current_parent->parent && current_parent->data_remaining == 0) {
                current_parent = current_parent->parent;
                level--;
            }
        }
    }

    if(stco != NULL) {
        adjust_stco_offset(stco, chunk_offset_adjust);
    }

    return root;
}

int main(int argc, char** argv) {

    FILE *m4a_file;
    char test[5] = "ftyp";
    uint32_t *test_convert = (uint32_t*)test;

    if(argc < 3) {
        printf("Usage: m4mudex <infilename> <outfilename>");
        exit(1);
    }

    m4a_file = fopen(argv[1], "rb");
    printf("\nChecking to see if source file has a meta box: \n");
    find_meta(m4a_file);
    rewind(m4a_file);

    printf("\n");

    if (m4a_file == NULL) {
        printf("Provide the name of an existing m4a file to parse\n");
        exit(1);
    }

    atom_t* m4a_tree = build_tree(m4a_file);

    printf("printing modified tree:\n");
    print_tree(m4a_tree);
    printf("\n");

    FILE *out_file;
    out_file = fopen(argv[2], "wb");
    output_tree(m4a_tree, out_file);
    fclose(out_file);

    printf("\nVerifying that output file has no meta box: \n");
    out_file = fopen(argv[2], "rb");
    find_meta(out_file);

}
<commit_msg>Updated and cleaned up<commit_after>/***
 * Removes the meta boxes from the provided mpeg4 source file, writing the result
 * out to a new file given the provided filename.
 *
 * This sample program only works for media files that stay within 32-bit box/file sizes.
 * If the file is larger than the 32-bit maximum, the following additions could be made:
 *
 * TODO
 * 1. Check for 64-bit boxes size encoding (atom size=1) and adjust accordingly.
 * 2. Find the co64 table instead of stco table, and modify those table entries.
 */

#include "stdio.h"
#include "stdint.h"
#include "stdlib.h"
#include "stddef.h"
#include "string.h"
#include <vector>

/* M4A atoms can be either data holders, or containers of other
 * atoms. Actually, it's slightly more complicated than that, since there
 * are a few choice atoms that are containers that also have data inside of them.
 * However, we don't need to worry about this in this utility, since the only
 * container that has that property is the "meta" container, but we're just
 * removing it, anyway; we don't need to recurse into it.
 *
 * According to the docs for the m4a file type, we can find meta in the following
 * places in the hierarchy:
 * meta
 * moov.udta.meta
 * moov.udta.trak.meta
 *
 * So, based on that information, we track make sure to check the
 * substructure of the necessary containers.
 */
const char *const containers_of_interest = "moov|udta|trak|mdia|minf|stbl";
typedef struct atom_t {
    atom_t* parent;
    uint32_t len;
    char name[5];
    uint32_t data_size;
    int32_t data_remaining;
    unsigned char* data;
    std::vector<atom_t*> children;
    bool active;
} atom_t;

/***
 * Find the next box (atom) starting from the current
 * position of the provided m4a file.
 *
 * Allocates memory for the atom if necessary, and returns
 * a new atom_t with information about the new atom.
 */
atom_t* get_next_box(FILE* m4a_file) {
    atom_t *atom = (atom_t*)malloc(sizeof(atom_t));

    /* Read size in big-endian order */
    fread(&atom->len, 4, 1, m4a_file);
    atom->active = true;
    atom->len = htonl(atom->len);

    fread(atom->name, 1, 4, m4a_file);

    /* If the standard length word is 1, then we
     * expect an 8-byte length immediately follow
     * the name.
     *
     * Also the header is effectively 16 bytes now. */
    //if(atom->len == 1) {
        /* Read in big-endian order */
    //    for(i = 7; i >= 0; i--) {
    //        fread(&(atom->len.bytes[i]), 1, 1, m4a_file);
    //    }
    //    atom->data_size = atom->len.word - 16;
    //} else {
        atom->data_size = atom->len - 8;
    //}

    /* Initialize the struct depending on whether
     * it's a container of interest or just a
     * data blob to pass through.
     */
    if(strstr(containers_of_interest, atom->name) != 0) {
        //If it's a container, mark the size in data_remaining so the main loop
        //knows how much to process
        atom->data = NULL;
        atom->data_remaining = atom->data_size;
    } else {
        //Otherwise, just throw the data in a char blob
        //to dump back out later
        atom->data = (unsigned char*)malloc(atom->data_size);;
        fread(atom->data, atom->data_size, 1, m4a_file);
        atom->data_remaining = 0;
    }
    return atom;
}

// A little function to look for meta tags in a less structured way
// Just used for testing
// Could possibly result in a false positive if the "meta" tag appears
// in binary data by chance, although my hunch is that this is unlikely.
int find_meta(FILE *m4a_file) {
    const char* target = "meta";
    unsigned int tmp;
    uint32_t i;
    for(i = 0; i < strlen(target); i++) {
        tmp <<= 8;
        tmp |= (unsigned char)target[i];
    }
    const unsigned int target_checksum = tmp; //Sum of characters in "meta"
    uint32_t checksum = 0;
    unsigned char c = 0;
    unsigned char buffer[8] = {0,0,0,0,0,0,0,0};
    int index = 0;
    while(fread(&c, 1, 1, m4a_file) > 0) {
        index++;
        buffer[index & 7] = c;
        checksum <<= 8;
        checksum |= c;
        if(checksum == target_checksum) {
            printf("Found 'meta' at position %lu\n", index - strlen(target));
            return index;
        }
    }
    printf("found no meta box in all %d positions\n",index);
    return -1;
}

/* Print out the atom tree representation
 * on stdout
 */
void print_tree_rec(atom_t* node, uint8_t level) {
    uint8_t i;
    for(i=0; i<level; i++) {
        printf(".");
    }
    //skip root content, it's not *really* an atom
    if(node->parent != NULL) {
        printf("%u %s\n", node->len, node->name);
    }
    for(i=0; i<node->children.size(); i++) {
        if(node->children[i]->active == true) {
            print_tree_rec(node->children[i], level+1);
        }
    }
}
void print_tree(atom_t* node) {
    print_tree_rec(node, 0);
}

//Write the atoms back out to file.
void output_tree(atom_t* node, FILE *out_file) {
    uint32_t i;

    //skip root content, it's not *really* an atom
    if(node->parent != NULL) {
        uint32_t out_len = htonl(node->len);
        fwrite(&out_len, 4, 1, out_file);
        fwrite(node->name, 4, 1, out_file);
        if(node->data_size > 0 && node->data != NULL) {
            fwrite(node->data, node->data_size, 1, out_file);
        }
    }

    for(i=0; i < node->children.size(); i++) {
        if(node->children[i]->active == true) {
            output_tree(node->children[i], out_file);
        }
    }
}

//Given an atom that we expect to be a stco block,
//and an offset_adjustment, fix the data portion of the
//atom so that the offsets are reduced by the adjustment
//amount
void adjust_stco_offset(atom_t *stco, int offset_adjust) {
    int i;
    //Offset past the version byte
    unsigned char* stco_data_ptr = (stco->data + 4);
    int stco_entries = htonl(*((uint32_t*)(stco_data_ptr)));

    //Ofset version bytes and length bytes
    stco_data_ptr = stco->data + 8;

    //Read the bytes in big-endian order,
    //subtract offset,
    //write back out.
    for(i = 0; i < stco_entries; i++) {
        uint32_t stco_offset = htonl(*((uint32_t*)(stco_data_ptr)));
        stco_offset -= offset_adjust;
        *((uint32_t*)stco_data_ptr) = htonl(stco_offset);
        stco_data_ptr += 4;
    }
}

//Strip meta boxes, returning the size of
//meta tags before mdat boxes for later
//adjustment.
void strip_meta_box_rec(atom_t *node, bool do_accumulate, uint32_t &accumulator, atom_t **stco) {
    uint32_t i;
    if(strncmp(node->name, "mdat", 4) == 0) {
        do_accumulate = false;
    } else if(strncmp(node->name, "stco", 4) == 0) {
        *stco = node;
    } else if(do_accumulate && strncmp(node->name, "meta", 4) == 0) {
        accumulator += node->len;
        node->active = false;
    }

    for(i = 0; i < node->children.size(); i++) {
        strip_meta_box_rec(node->children[i], do_accumulate, accumulator, stco);
    }
}
void strip_meta_box(atom_t *node) {
    uint32_t offset_adjust = 0;
    atom_t* stco;
    strip_meta_box_rec(node, true, offset_adjust, &stco);
    adjust_stco_offset(stco, offset_adjust);
}

//Create a representation of the tree structure of the atoms
//This function is called recursively. If an atom is marked as a
//container, move through the data section of the atom sub-atom
//at a time, otherwise just dump the whole data thing into a blob.
atom_t* build_tree(FILE* m4a_file) {

    //Place to hold the current working atom.
    atom_t *atom;

    //Create an abstract root node to hold the top-level
    //atom list.
    atom_t *root = (atom_t*)calloc(sizeof(atom_t), 1);

    atom_t *current_parent = root;

    /* Loop through the rest of the atoms */
    while((atom = get_next_box(m4a_file))->len > 0) {
        //Set the parent of the newly created atom
        atom->parent = current_parent;

        //Add new atom to the current parent list.
        current_parent->children.push_back(atom);

        //Subtract size of current atom from
        //the data_remaining of the parent
        //Note: this must occur before the next step
        //which might change the level. Don't try to
        //include it in the following step.
        if(current_parent != root) {
            current_parent->data_remaining -= atom->len;
        }

        //If the atom has data_remaining set, then must have some children
        if(atom->data_remaining > 0) {
            current_parent = atom;
        }

        //Check if we have data remaining in the parent.
        //If not, if atom was the last one in the parent.
        //So, move back up one level
        if(current_parent != root) {
            //Make sure we haven't overrun any expected sizes in the parent
            if(current_parent->data_remaining < 0) {
                printf("Something wrong: child atom overruns the parent size.");
                printf("Parent name is: %s\n",current_parent->name);
                exit(0);
            }

            //We're done getting the children of this parent, move back up.
            while (current_parent && current_parent->parent && current_parent->data_remaining == 0) {
                current_parent = current_parent->parent;
            }
        }
    }

    return root;
}

int main(int argc, char** argv) {
    FILE *m4a_file;
    FILE *out_file;

    //Check inputs, open file, check for success
    if(argc < 3) {
        printf("Usage: m4mudex <infilename> <outfilename>");
        exit(1);
    }
    m4a_file = fopen(argv[1], "rb");
    if (m4a_file == NULL) {
        printf("Provide the name of an existing m4a file to parse\n");
        exit(1);
    }

    //Quick sanity check on input file
    printf("\nChecking to see if source file has a meta box: \n");
    find_meta(m4a_file);
    rewind(m4a_file);

    //Build the tree
    atom_t* m4a_tree = build_tree(m4a_file);

    //Show the tree
    printf("printing original tree:\n");
    print_tree(m4a_tree);
    printf("\n");

    //Get rid of metas and adjust offsets
    strip_meta_box(m4a_tree);

    //Show the modified tree
    printf("printing modifiedtree:\n");
    print_tree(m4a_tree);
    printf("\n");

    //Write out the modified tree.
    out_file = fopen(argv[2], "wb");
    output_tree(m4a_tree, out_file);
    fclose(out_file);

    //Verify the output file
    printf("\nVerifying that output file has no meta box: \n");
    out_file = fopen(argv[2], "rb");
    find_meta(out_file);

}
<|endoftext|>


<commit_before>#include "./center_force.h"
#include <vector>
#include "./label_state.h"

namespace Forces
{
CenterForce::CenterForce() : Force("Center", 0.1f)
{
}

void CenterForce::beforeAll(std::vector<LabelState> &labels)
{
  Eigen::Vector2f anchorPositionSum;
  for (auto &labelState : labels)
    anchorPositionSum += labelState.anchorPosition2D;

  if (labels.size() > 0)
    averageCenter = anchorPositionSum / labels.size();
  else
    averageCenter = Eigen::Vector2f(0, 0);
}

Eigen::Vector2f CenterForce::calculate(LabelState &label,
                                       std::vector<LabelState> &labels)
{
  return (label.anchorPosition2D - averageCenter).normalized();
}

}  // namespace Forces
<commit_msg>Fix uninitialized local variable.<commit_after>#include "./center_force.h"
#include <vector>
#include "./label_state.h"

namespace Forces
{
CenterForce::CenterForce() : Force("Center", 0.1f)
{
}

void CenterForce::beforeAll(std::vector<LabelState> &labels)
{
  Eigen::Vector2f anchorPositionSum(0, 0);
  for (auto &labelState : labels)
    anchorPositionSum += labelState.anchorPosition2D;

  if (labels.size() > 0)
    averageCenter = anchorPositionSum / labels.size();
  else
    averageCenter = Eigen::Vector2f(0, 0);
}

Eigen::Vector2f CenterForce::calculate(LabelState &label,
                                       std::vector<LabelState> &labels)
{
  return (label.anchorPosition2D - averageCenter).normalized();
}

}  // namespace Forces
<|endoftext|>


<commit_before>#include "geometry.hpp"

Segment::Segment()
{
    p1=sf::Vector2f(0.f,0.f);
    p2=sf::Vector2f(0.f,0.f);
}

Segment::Segment(sf::Vector2f pointA, sf::Vector2f pointB)
{
    p1=pointA;
    p2=pointB;
}

const sf::Vector2f Segment::intersection_time(const Segment &other) const
{
    auto dir1 = p2 - p1;
    auto dir2 = other.p2 - other.p1;
    /*
    Now we try to solve p1 + t1 * dir1 = other.p1 + t2 * dir2
    This is a system of two linear equations
    */
    float a = dir1.x;
    float b = -dir2.x;
    float c = dir1.y;
    float d = -dir2.y;
    float det = (a * d - b * c);
    if (-epsilon <= det && det <= epsilon) {
        return sf::Vector2f(-42, -42); // Segments are parallel
    }
    float e = other.p1.x - p1.x;
    float f = other.p1.y - p1.x;
    float t1 = (d * e - b * f) / det;
    float t2 = (-c * e + a * f) / det;
    return sf::Vector2f(t1, t2);
}

const sf::Vector2f Segment::intersection(const Segment &other) const {
    sf::Vector2f it = intersection_time(other);
    if (check(it.x) && check(it.y)) {
        // Intersection
        return interp(p1, p2, it.x);
    }
    return sf::Vector2f(-42, -42);
};

void Segment::intersection_triangle(const sf::Vector2f lumiere,
        const Segment &tri, std::vector<Segment> &result) {
    Segment tri1 = Segment(lumiere, tri.p1);
    Segment tri2 = Segment(lumiere, tri.p2);
    sf::Vector2f it1 = intersection_time(tri1);
    sf::Vector2f it2 = intersection_time(tri2);
    sf::Vector2f it3 = intersection_time(tri);
    sf::Vector2f si1 = interp(lumiere, tri.p1, it1.y);
    sf::Vector2f si2 = interp(lumiere, tri.p2, it2.y);
    sf::Vector2f si3 = interp(tri.p1, tri.p2, it3.y);

    if (!(check(it1.y) || check(it2.y) || check(it3.y))) {
        // La droite du segment ne passe pas dans le triangle
        result.push_back(tri);
        return;
    }

    if (!check_strict(it3.y)) {
        // La droite coupe les deux cotes principaux
        float u, v;
        sf::Vector2f pp1, pp2;
        if (it1.x < it2.x) {
            pp1 = p1; pp2 = p2; u = it1.x; v = it2.x;
        } else {
            pp1 = p2; pp2 = p1; u = it2.x; v = it1.x;
        }
        if (v < epsilon || u > 1.f - epsilon) {
            // Segment à l'extérieur du triangle
            result.push_back(tri);
            return;
        }
        sf::Vector2f inter1 = tri.intersection(Segment(lumiere, pp1));
        sf::Vector2f inter2 = tri.intersection(Segment(lumiere, pp2));
        if (-epsilon <= u && v < 1.f + epsilon) {
            // Completement a l'interieur
            result.push_back(Segment(tri.p1, inter1));
            result.push_back(Segment(pp1, pp2));
            result.push_back(Segment(inter2, tri.p2));
            return;
        }
        // On intersecte un seul cote
        if (check(it1.x)) {
            // On intersecte cote 1
            result.push_back(Segment(si1, pp2));
            result.push_back(Segment(inter2, tri.p2));
            return;
        } else {
            // On intersecte cote 2
            result.push_back(Segment(tri.p1, inter1));
            result.push_back(Segment(pp1, si2));
            return;
        }
    }

    if (!check_strict(it1.y)) {
        // On coupe cote 2 et le bout
        float u, v;
        sf::Vector2f pp1, pp2;
        if (it3.x < it2.x) {
            pp1 = p1; pp2 = p2; u = it3.x; v = it2.x;
        } else {
            pp1 = p2; pp2 = p1; u = it2.x; v = it3.x;
        }
        if (v < epsilon || u > 1.f - epsilon) {
            // Segment à l'extérieur du triangle
            result.push_back(tri);
            return;
        }
        sf::Vector2f inter1 = tri.intersection(Segment(lumiere, pp1));
        sf::Vector2f inter2 = tri.intersection(Segment(lumiere, pp2));
        if (-epsilon <= u && v < 1.f + epsilon) {
            // Completement a l'interieur
            result.push_back(Segment(tri.p1, inter1));
            result.push_back(Segment(pp1, pp2));
            result.push_back(Segment(inter2, tri.p2));
            return;
        }
        // On intersecte un seul cote
        if (check(it3.x)) {
            // On intersecte le bout
            result.push_back(Segment(tri.p1, si3));
            result.push_back(Segment(si3, pp2));
            result.push_back(Segment(inter2, tri.p2));
            return;
        } else {
            // On intersecte cote 2
            result.push_back(Segment(tri.p1, inter1));
            result.push_back(Segment(pp1, si2));
            return;
        }
    } else {
        // On coupe cote 1 et le bout
        float u, v;
        sf::Vector2f pp1, pp2;
        if (it1.x < it3.x) {
            pp1 = p1; pp2 = p2; u = it1.x; v = it3.x;
        } else {
            pp1 = p2; pp2 = p1; u = it3.x; v = it1.x;
        }
        if (v < epsilon || u > 1.f - epsilon) {
            // Segment à l'extérieur du triangle
            result.push_back(tri);
            return;
        }
        sf::Vector2f inter1 = tri.intersection(Segment(lumiere, pp1));
        sf::Vector2f inter2 = tri.intersection(Segment(lumiere, pp2));
        if (-epsilon <= u && v < 1.f + epsilon) {
            // Completement a l'interieur
            result.push_back(Segment(tri.p1, inter1));
            result.push_back(Segment(pp1, pp2));
            result.push_back(Segment(inter2, tri.p2));
            return;
        }
        // On intersecte un seul cote
        if (check(it3.x)) {
            // On intersecte le bout
            result.push_back(Segment(tri.p1, inter1));
            result.push_back(Segment(pp1, si3));
            result.push_back(Segment(si3, tri.p2));
            return;
        } else {
            // On intersecte cote 1
            result.push_back(Segment(si1, pp2));
            result.push_back(Segment(inter2, tri.p2));
            return;
        }
    }
};

<commit_msg>Triangle splitter should work<commit_after>#include "geometry.hpp"

Segment::Segment()
{
    p1=sf::Vector2f(0.f,0.f);
    p2=sf::Vector2f(0.f,0.f);
}

Segment::Segment(sf::Vector2f pointA, sf::Vector2f pointB)
{
    p1=pointA;
    p2=pointB;
}

const sf::Vector2f Segment::intersection_time(const Segment &other) const
{
    auto dir1 = p2 - p1;
    auto dir2 = other.p2 - other.p1;
    /*
    Now we try to solve p1 + t1 * dir1 = other.p1 + t2 * dir2
    This is a system of two linear equations
    */
    float a = dir1.x;
    float b = -dir2.x;
    float c = dir1.y;
    float d = -dir2.y;
    float det = (a * d - b * c);
    if (-epsilon <= det && det <= epsilon) {
        return sf::Vector2f(-42, -42); // Segments are parallel
    }
    float e = other.p1.x - p1.x;
    float f = other.p1.y - p1.x;
    float t1 = (d * e - b * f) / det;
    float t2 = (-c * e + a * f) / det;
    return sf::Vector2f(t1, t2);
}

const sf::Vector2f Segment::intersection(const Segment &other) const {
    sf::Vector2f it = intersection_time(other);
    if (check(it.x) && check(it.y)) {
        // Intersection
        return interp(p1, p2, it.x);
    }
    return sf::Vector2f(-42, -42);
};

void Segment::intersection_triangle(const sf::Vector2f lumiere,
        const Segment &tri, std::vector<Segment> &result) {
    Segment tri1 = Segment(lumiere, tri.p1);
    Segment tri2 = Segment(lumiere, tri.p2);
    sf::Vector2f it1 = intersection_time(tri1);
    sf::Vector2f it2 = intersection_time(tri2);
    sf::Vector2f it3 = intersection_time(tri);
    sf::Vector2f si1 = interp(lumiere, tri.p1, it1.y);
    sf::Vector2f si2 = interp(lumiere, tri.p2, it2.y);
    sf::Vector2f si3 = interp(tri.p1, tri.p2, it3.y);

    if (!(check(it1.y) || check(it2.y) || check(it3.y))) {
        // La droite du segment ne passe pas dans le triangle
        result.push_back(tri);
        return;
    }

    if (!check_strict(it3.y)) {
        // La droite coupe les deux cotes principaux
        float u, v;
        sf::Vector2f pp1, pp2;
        if (it1.x < it2.x) {
            pp1 = p1; pp2 = p2; u = it1.x; v = it2.x;
        } else {
            pp1 = p2; pp2 = p1; u = it2.x; v = it1.x;
        }
        if (v < epsilon || u > 1.f - epsilon) {
            // Segment à l'extérieur du triangle
            result.push_back(tri);
            return;
        }
        sf::Vector2f inter1 = tri.intersection(Segment(lumiere, pp1));
        sf::Vector2f inter2 = tri.intersection(Segment(lumiere, pp2));
        if (-epsilon <= u && v < 1.f + epsilon) {
            // Completement a l'interieur
            result.push_back(Segment(tri.p1, inter1));
            result.push_back(Segment(pp1, pp2));
            result.push_back(Segment(inter2, tri.p2));
            return;
        }
        // On intersecte un seul cote
        if (check(it1.x)) {
            // On intersecte cote 1
            result.push_back(Segment(si1, pp2));
            result.push_back(Segment(inter2, tri.p2));
            return;
        } else {
            // On intersecte cote 2
            result.push_back(Segment(tri.p1, inter1));
            result.push_back(Segment(pp1, si2));
            return;
        }
    }

    if (!check_strict(it1.y)) {
        // On coupe cote 2 et le bout
        float u, v;
        sf::Vector2f pp1, pp2;
        if (it3.x < it2.x) {
            pp1 = p1; pp2 = p2; u = it3.x; v = it2.x;
        } else {
            pp1 = p2; pp2 = p1; u = it2.x; v = it3.x;
        }
        if (v < epsilon || u > 1.f - epsilon) {
            // Segment à l'extérieur du triangle
            result.push_back(tri);
            return;
        }
        sf::Vector2f inter1 = tri.intersection(Segment(lumiere, pp1));
        sf::Vector2f inter2 = tri.intersection(Segment(lumiere, pp2));
        if (-epsilon <= u && v < 1.f + epsilon) {
            // Completement a l'interieur
            result.push_back(Segment(tri.p1, inter1));
            result.push_back(Segment(pp1, pp2));
            result.push_back(Segment(inter2, tri.p2));
            return;
        }
        // On intersecte un seul cote
        if (check(it3.x)) {
            // On intersecte le bout
            result.push_back(Segment(tri.p1, si3));
            result.push_back(Segment(si3, pp2));
            result.push_back(Segment(inter2, tri.p2));
            return;
        } else {
            // On intersecte cote 2
            result.push_back(Segment(tri.p1, inter1));
            result.push_back(Segment(pp1, si2));
            return;
        }
    } else {
        // On coupe cote 1 et le bout
        float u, v;
        sf::Vector2f pp1, pp2;
        if (it1.x < it3.x) {
            pp1 = p1; pp2 = p2; u = it1.x; v = it3.x;
        } else {
            pp1 = p2; pp2 = p1; u = it3.x; v = it1.x;
        }
        if (v < epsilon || u > 1.f - epsilon) {
            // Segment à l'extérieur du triangle
            result.push_back(tri);
            return;
        }
        sf::Vector2f inter1 = tri.intersection(Segment(lumiere, pp1));
        sf::Vector2f inter2 = tri.intersection(Segment(lumiere, pp2));
        if (-epsilon <= u && v < 1.f + epsilon) {
            // Completement a l'interieur
            result.push_back(Segment(tri.p1, inter1));
            result.push_back(Segment(pp1, pp2));
            result.push_back(Segment(inter2, tri.p2));
            return;
        }
        // On intersecte un seul cote
        if (check(it3.x)) {
            // On intersecte le bout
            result.push_back(Segment(tri.p1, inter1));
            result.push_back(Segment(pp1, si3));
            result.push_back(Segment(si3, tri.p2));
            return;
        } else {
            // On intersecte cote 1
            result.push_back(Segment(si1, pp2));
            result.push_back(Segment(inter2, tri.p2));
            return;
        }
    }
};
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: imapdlg.hxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 17:56:14 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _IMAPDLG_HXX_
#define _IMAPDLG_HXX_

#ifndef _SVTOOLS_INETTBC_HXX
#include <svtools/inettbc.hxx>
#endif

#ifndef _SFX_CHILDWIN_HXX //autogen
#include <sfx2/childwin.hxx>
#endif

#ifndef _SFXCTRLITEM_HXX //autogen
#include <sfx2/ctrlitem.hxx>
#endif

#ifndef _BASEDLGS_HXX //autogen
#include <sfx2/basedlgs.hxx>
#endif

#ifndef _FIXED_HXX //autogen
#include <vcl/fixed.hxx>
#endif

#ifndef _COMBOBOX_HXX //autogen
#include <vcl/combobox.hxx>
#endif

#ifndef _EDIT_HXX //autogen
#include <vcl/edit.hxx>
#endif

#ifndef _TOOLBOX_HXX //autogen
#include <vcl/toolbox.hxx>
#endif

#ifndef _STATUS_HXX //autogen
#include <vcl/status.hxx>
#endif

#ifndef INCLUDED_SVXDLLAPI_H
#include "svx/svxdllapi.h"
#endif

#ifndef _GOMISC_HXX
class ImageMap;
#endif

/*************************************************************************
|*
|* Ableitung vom SfxChildWindow als "Behaelter" fuer Float
|*
\************************************************************************/

class Graphic;
class TargetList;

class SVX_DLLPUBLIC SvxIMapDlgChildWindow : public SfxChildWindow
{
 public:

    SvxIMapDlgChildWindow( Window*, USHORT, SfxBindings*, SfxChildWinInfo* );

    SFX_DECL_CHILDWINDOW( SvxIMapDlgChildWindow );

    static void UpdateIMapDlg( const Graphic& rGraphic, const ImageMap* pImageMap = NULL,
                               const TargetList* pTargetList = NULL, void* pEditingObj = NULL );
};

#ifndef _REDUCED_IMAPDLG_HXX_
#define _REDUCED_IMAPDLG_HXX_

/*************************************************************************
|*
|*
|*
\************************************************************************/

class SvxIMapDlg;

class SvxIMapDlgItem : public SfxControllerItem
{
    SvxIMapDlg& rIMap;

protected:

    virtual void StateChanged( USHORT nSID, SfxItemState eState,
                               const SfxPoolItem* pState );

public:

    SvxIMapDlgItem( USHORT nId, SvxIMapDlg& rIMapDlg, SfxBindings& rBindings );
};

/*************************************************************************
|*
|*
|*
\************************************************************************/

class IMapOwnData;
class IMapWindow;

class SVX_DLLPUBLIC SvxIMapDlg : public SfxModelessDialog // SfxFloatingWindow
{
    friend class IMapOwnData;
    friend class IMapWindow;

    ToolBox             aTbxIMapDlg1;
    FixedText           aFtURL;
    SvtURLBox           maURLBox;
    FixedText           aFtText;
    Edit                aEdtText;
    FixedText           maFtTarget;
    ComboBox            maCbbTarget;
    StatusBar           aStbStatus;
    ImageList           maImageList;
    ImageList           maImageListH;

    Size                aLastSize;
    IMapWindow*         pIMapWnd;
    IMapOwnData*        pOwnData;
    void*               pCheckObj;
    SvxIMapDlgItem      aIMapItem;

    virtual void        Resize();
    virtual BOOL        Close();

#ifdef _IMAPDLG_PRIVATE

                        DECL_LINK( TbxClickHdl, ToolBox* );
                        DECL_LINK( InfoHdl, IMapWindow* );
                        DECL_LINK( MousePosHdl, IMapWindow* );
                        DECL_LINK( GraphSizeHdl, IMapWindow* );
                        DECL_LINK( URLModifyHdl, void* );
                        DECL_LINK( URLLoseFocusHdl, void* );
                        DECL_LINK( UpdateHdl, Timer* );
                        DECL_LINK( TbxUpdateHdl, Timer* );
                        DECL_LINK( StateHdl, IMapWindow* );
                        DECL_LINK( MiscHdl, void* );

    void                DoOpen();
    BOOL                DoSave();

#endif

public:

                        SvxIMapDlg( SfxBindings *pBindings, SfxChildWindow *pCW,
                                    Window* pParent, const ResId& rResId );
                        ~SvxIMapDlg();

    void                SetExecState( BOOL bEnable );

    void                SetGraphic( const Graphic& rGraphic );

    void                SetEditingObject( void* pObj ) { pCheckObj = pObj; }
    const void*         GetEditingObject() const { return pCheckObj; }

    void                SetImageMap( const ImageMap& rImageMap );
    const ImageMap&     GetImageMap() const;

    void                SetTargetList( const TargetList& rTargetList );
    const TargetList&   GetTargetList() const;

    void                Update( const Graphic& rGraphic, const ImageMap* pImageMap = NULL,
                                const TargetList* pTargetList = NULL, void* pEditingObj = NULL );

    virtual void        KeyInput( const KeyEvent& rKEvt );

    virtual void DataChanged( const DataChangedEvent& rDCEvt );
    void ApplyImageList();
};

/*************************************************************************
|*
|* Defines
|*
\************************************************************************/

#define SVXIMAPDLG() ( (SvxIMapDlg*) ( SfxViewFrame::Current()->GetChildWindow(         \
                        SvxIMapDlgChildWindow::GetChildWindowId() )->   \
                        GetWindow() ) )

#endif // _REDUCED_IMAPDLG_HXX_
#endif // _IMAPDLG_HXX_

<commit_msg>INTEGRATION: CWS sb59 (1.9.488); FILE MERGED 2006/08/03 13:47:04 cl 1.9.488.1: removed compiler warnings<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: imapdlg.hxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: obo $ $Date: 2006-10-12 11:45:06 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _IMAPDLG_HXX_
#define _IMAPDLG_HXX_

#ifndef _SVTOOLS_INETTBC_HXX
#include <svtools/inettbc.hxx>
#endif

#ifndef _SFX_CHILDWIN_HXX //autogen
#include <sfx2/childwin.hxx>
#endif

#ifndef _SFXCTRLITEM_HXX //autogen
#include <sfx2/ctrlitem.hxx>
#endif

#ifndef _BASEDLGS_HXX //autogen
#include <sfx2/basedlgs.hxx>
#endif

#ifndef _FIXED_HXX //autogen
#include <vcl/fixed.hxx>
#endif

#ifndef _COMBOBOX_HXX //autogen
#include <vcl/combobox.hxx>
#endif

#ifndef _EDIT_HXX //autogen
#include <vcl/edit.hxx>
#endif

#ifndef _TOOLBOX_HXX //autogen
#include <vcl/toolbox.hxx>
#endif

#ifndef _STATUS_HXX //autogen
#include <vcl/status.hxx>
#endif

#ifndef INCLUDED_SVXDLLAPI_H
#include "svx/svxdllapi.h"
#endif

#ifndef _GOMISC_HXX
class ImageMap;
#endif

/*************************************************************************
|*
|* Ableitung vom SfxChildWindow als "Behaelter" fuer Float
|*
\************************************************************************/

class Graphic;
class TargetList;

class SVX_DLLPUBLIC SvxIMapDlgChildWindow : public SfxChildWindow
{
 public:

    SvxIMapDlgChildWindow( Window*, USHORT, SfxBindings*, SfxChildWinInfo* );

    SFX_DECL_CHILDWINDOW( SvxIMapDlgChildWindow );

    static void UpdateIMapDlg( const Graphic& rGraphic, const ImageMap* pImageMap = NULL,
                               const TargetList* pTargetList = NULL, void* pEditingObj = NULL );
};

#ifndef _REDUCED_IMAPDLG_HXX_
#define _REDUCED_IMAPDLG_HXX_

/*************************************************************************
|*
|*
|*
\************************************************************************/

class SvxIMapDlg;

class SvxIMapDlgItem : public SfxControllerItem
{
    SvxIMapDlg& rIMap;

protected:

    virtual void StateChanged( USHORT nSID, SfxItemState eState,
                               const SfxPoolItem* pState );

public:

    SvxIMapDlgItem( USHORT nId, SvxIMapDlg& rIMapDlg, SfxBindings& rBindings );
};

/*************************************************************************
|*
|*
|*
\************************************************************************/

class IMapOwnData;
class IMapWindow;

class SVX_DLLPUBLIC SvxIMapDlg : public SfxModelessDialog // SfxFloatingWindow
{
    friend class IMapOwnData;
    friend class IMapWindow;
    using Window::Update;

    ToolBox             aTbxIMapDlg1;
    FixedText           aFtURL;
    SvtURLBox           maURLBox;
    FixedText           aFtText;
    Edit                aEdtText;
    FixedText           maFtTarget;
    ComboBox            maCbbTarget;
    StatusBar           aStbStatus;
    ImageList           maImageList;
    ImageList           maImageListH;

    Size                aLastSize;
    IMapWindow*         pIMapWnd;
    IMapOwnData*        pOwnData;
    void*               pCheckObj;
    SvxIMapDlgItem      aIMapItem;

    virtual void        Resize();
    virtual BOOL        Close();

#ifdef _IMAPDLG_PRIVATE

                        DECL_LINK( TbxClickHdl, ToolBox* );
                        DECL_LINK( InfoHdl, IMapWindow* );
                        DECL_LINK( MousePosHdl, IMapWindow* );
                        DECL_LINK( GraphSizeHdl, IMapWindow* );
                        DECL_LINK( URLModifyHdl, void* );
                        DECL_LINK( URLLoseFocusHdl, void* );
                        DECL_LINK( UpdateHdl, Timer* );
                        DECL_LINK( TbxUpdateHdl, Timer* );
                        DECL_LINK( StateHdl, IMapWindow* );
                        DECL_LINK( MiscHdl, void* );

    void                DoOpen();
    BOOL                DoSave();

#endif

public:

                        SvxIMapDlg( SfxBindings *pBindings, SfxChildWindow *pCW,
                                    Window* pParent, const ResId& rResId );
                        ~SvxIMapDlg();

    void                SetExecState( BOOL bEnable );

    void                SetGraphic( const Graphic& rGraphic );

    void                SetEditingObject( void* pObj ) { pCheckObj = pObj; }
    const void*         GetEditingObject() const { return pCheckObj; }

    void                SetImageMap( const ImageMap& rImageMap );
    const ImageMap&     GetImageMap() const;

    void                SetTargetList( const TargetList& rTargetList );
    const TargetList&   GetTargetList() const;

    void                Update( const Graphic& rGraphic, const ImageMap* pImageMap = NULL,
                                const TargetList* pTargetList = NULL, void* pEditingObj = NULL );

    virtual void        KeyInput( const KeyEvent& rKEvt );

    virtual void DataChanged( const DataChangedEvent& rDCEvt );
    void ApplyImageList();
};

/*************************************************************************
|*
|* Defines
|*
\************************************************************************/

#define SVXIMAPDLG() ( (SvxIMapDlg*) ( SfxViewFrame::Current()->GetChildWindow(         \
                        SvxIMapDlgChildWindow::GetChildWindowId() )->   \
                        GetWindow() ) )

#endif // _REDUCED_IMAPDLG_HXX_
#endif // _IMAPDLG_HXX_

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: dbgoutsw.hxx,v $
 *
 *  $Revision: 1.15 $
 *
 *  last change: $Author: rt $ $Date: 2005-11-08 17:11:44 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef __DBGOUTSW_HXX
#define __DBGOUTSW_HXX

#ifdef DEBUG

#include <hash_map>
#include <tox.hxx>
class String;
class SwNode;
class SwTxtAttr;
class SwpHints;
class SfxPoolItem;
class SfxItemSet;
struct SwPosition;
class SwPaM;
class SwNodeNum;
class SwUndo;
class SwUndos;
class SwRect;
class SwFrmFmt;
class SwFrmFmts;
class SwNodes;
class SwRewriter;
class SwNumRuleTbl;
class SwNumRule;
class SwOutlineNodes;
class SwTxtFmtColl;

#define DBG_OUT_HERE printf("%s(%d):", __FILE__, __LINE__)
#define DBG_OUT_HERE_FN printf("%s(%d) %s:", __FILE__, __LINE__, __FUNCTION__)
#define DBG_OUT_HERE_LN printf("%s(%d)\n", __FILE__, __LINE__)
#define DBG_OUT_HERE_FN_LN printf("%s(%d) %s\n", __FILE__, __LINE__, __FUNCTION__)
#define DBG_OUT(x) printf("%s\n", dbg_out(x))
#define DBG_OUT_LN(x) printf("%s(%d): %s\n", __FILE__, __LINE__, dbg_out(x))
#define DBG_OUT_FN_LN(x) printf("%s: %s\n", __FUNCTION__, dbg_out(x))

extern bool bDbgOutStdErr;
extern bool bDbgOutPrintAttrSet;

const char * dbg_out(const void * pVoid);
const char * dbg_out(const String & aStr);
const char * dbg_out(const SwRect & rRect);
const char * dbg_out(const SwFrmFmt & rFrmFmt);
const char * dbg_out(const SwNode & rNode);
const char * dbg_out(const SwTxtAttr & rAttr);
const char * dbg_out(const SwpHints &rHints);
const char * dbg_out(const SfxPoolItem & rItem);
const char * dbg_out(const SfxPoolItem * pItem);
const char * dbg_out(const SfxItemSet & rSet);
const char * dbg_out(SwNodes & rNodes);
// const char * dbg_out(SwOutlineNodes & rNodes);
const char * dbg_out(const SwPosition & rPos);
const char * dbg_out(const SwPaM & rPam);
const char * dbg_out(const SwNodeNum & rNum);
const char * dbg_out(const SwUndo & rUndo);
const char * dbg_out(const SwUndos & rUndos);
const char * dbg_out(const SwRewriter & rRewriter);
const char * dbg_out(const SwNumRule & rRule);
const char * dbg_out(const SwTxtFmtColl & rFmt);
const char * dbg_out(const SwFrmFmts & rFrmFmts);
const char * dbg_out(const SwNumRuleTbl & rTbl);

template<typename tKey, typename tMember, typename fHashFunction>
String lcl_dbg_out(const std::hash_map<tKey, tMember, fHashFunction> & rMap)
{
    String aResult("[", RTL_TEXTENCODING_ASCII_US);

    typename std::hash_map<tKey, tMember, fHashFunction>::const_iterator aIt;

    for (aIt = rMap.begin(); aIt != rMap.end(); aIt++)
    {
        if (aIt != rMap.begin())
            aResult += String(", ", RTL_TEXTENCODING_ASCII_US);

        aResult += aIt->first;

        char sBuffer[256];
        sprintf(sBuffer, "(%p)", aIt->second);
        aResult += String(sBuffer, RTL_TEXTENCODING_ASCII_US);
    }

    aResult += String("]", RTL_TEXTENCODING_ASCII_US);

    return aResult;
}

template<typename tKey, typename tMember, typename fHashFunction>
const char * dbg_out(const std::hash_map<tKey, tMember, fHashFunction> & rMap)
{
    return dbg_out(lcl_dbg_out(rMap));
}
const char * dbg_out(const SwFormToken & rToken);
const char * dbg_out(const SwFormTokens & rTokens);
#endif // DEBUG
#endif // __DBGOUTSW_HXX
<commit_msg>INTEGRATION: CWS writercorehandoff (1.12.172); FILE MERGED 2005/12/20 15:00:15 tra 1.12.172.4: RESYNC: (1.14-1.15); FILE MERGED 2005/09/13 11:19:33 tra 1.12.172.3: RESYNC: (1.13-1.14); FILE MERGED 2005/07/11 06:08:27 tra 1.12.172.2: RESYNC: (1.12-1.13); FILE MERGED 2005/06/06 07:07:21 tra 1.12.172.1: Unnecessary includes removed #i50348#<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: dbgoutsw.hxx,v $
 *
 *  $Revision: 1.16 $
 *
 *  last change: $Author: hr $ $Date: 2006-08-14 15:19:01 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef __DBGOUTSW_HXX
#define __DBGOUTSW_HXX

#ifdef DEBUG

#include <hash_map>
#include <tox.hxx>
class String;
class SwNode;
class SwTxtAttr;
class SwpHints;
class SfxPoolItem;
class SfxItemSet;
struct SwPosition;
class SwPaM;
class SwNodeNum;
class SwUndo;
class SwUndos;
class SwRect;
class SwFrmFmt;
class SwFrmFmts;
class SwNodes;
class SwRewriter;
class SwNumRuleTbl;
class SwNumRule;
class SwOutlineNodes;
class SwTxtFmtColl;

#define DBG_OUT_HERE printf("%s(%d):", __FILE__, __LINE__)
#define DBG_OUT_HERE_FN printf("%s(%d) %s:", __FILE__, __LINE__, __FUNCTION__)
#define DBG_OUT_HERE_LN printf("%s(%d)\n", __FILE__, __LINE__)
#define DBG_OUT_HERE_FN_LN printf("%s(%d) %s\n", __FILE__, __LINE__, __FUNCTION__)
#define DBG_OUT(x) printf("%s\n", dbg_out(x))
#define DBG_OUT_LN(x) printf("%s(%d): %s\n", __FILE__, __LINE__, dbg_out(x))
#define DBG_OUT_FN_LN(x) printf("%s: %s\n", __FUNCTION__, dbg_out(x))

extern bool bDbgOutStdErr;
extern bool bDbgOutPrintAttrSet;

const char * dbg_out(const void * pVoid);
const char * dbg_out(const String & aStr);
const char * dbg_out(const SwRect & rRect);
const char * dbg_out(const SwFrmFmt & rFrmFmt);
const char * dbg_out(const SwNode & rNode);
const char * dbg_out(const SwTxtAttr & rAttr);
const char * dbg_out(const SwpHints &rHints);
const char * dbg_out(const SfxPoolItem & rItem);
const char * dbg_out(const SfxPoolItem * pItem);
const char * dbg_out(const SfxItemSet & rSet);
const char * dbg_out(SwNodes & rNodes);
// const char * dbg_out(SwOutlineNodes & rNodes);
const char * dbg_out(const SwPosition & rPos);
const char * dbg_out(const SwPaM & rPam);
const char * dbg_out(const SwNodeNum & rNum);
const char * dbg_out(const SwUndo & rUndo);
const char * dbg_out(const SwUndos & rUndos);
const char * dbg_out(const SwRewriter & rRewriter);
const char * dbg_out(const SwNumRule & rRule);
const char * dbg_out(const SwTxtFmtColl & rFmt);
const char * dbg_out(const SwFrmFmts & rFrmFmts);
const char * dbg_out(const SwNumRuleTbl & rTbl);

template<typename tKey, typename tMember, typename fHashFunction>
String lcl_dbg_out(const std::hash_map<tKey, tMember, fHashFunction> & rMap)
{
    String aResult("[", RTL_TEXTENCODING_ASCII_US);

    typename std::hash_map<tKey, tMember, fHashFunction>::const_iterator aIt;

    for (aIt = rMap.begin(); aIt != rMap.end(); aIt++)
    {
        if (aIt != rMap.begin())
            aResult += String(", ", RTL_TEXTENCODING_ASCII_US);

        aResult += aIt->first;

        char sBuffer[256];
        sprintf(sBuffer, "(%p)", aIt->second);
        aResult += String(sBuffer, RTL_TEXTENCODING_ASCII_US);
    }

    aResult += String("]", RTL_TEXTENCODING_ASCII_US);

    return aResult;
}

template<typename tKey, typename tMember, typename fHashFunction>
const char * dbg_out(const std::hash_map<tKey, tMember, fHashFunction> & rMap)
{
    return dbg_out(lcl_dbg_out(rMap));
}
const char * dbg_out(const SwFormToken & rToken);
const char * dbg_out(const SwFormTokens & rTokens);
#endif // DEBUG
#endif // __DBGOUTSW_HXX
<|endoftext|>


<commit_before>/**
 * A set of functions and method which assist the main function to set up
 * the requested feature of the Intelligent Automation System.
 *
 * @date                    Jul 2, 2014
 * @author                  Joeri HERMANS
 * @version                 0.1
 *
 * Copyright 2013 Joeri HERMANS
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// BEGIN Includes. ///////////////////////////////////////////////////

// System dependencies.
#include <cassert>
#include <cstring>
#include <string>
#include <iostream>
#include <openssl/conf.h>
#include <openssl/engine.h>
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

// Application dependencies.
#include <ias/application/constants.h>
#include <ias/application/client/client_application.h>
#include <ias/application/controller_application.h>
#include <ias/application/server_application.h>
#include <ias/main.h>
#include <ias/util/util.h>
#include <ias/logger/logger.h>

// END Includes. /////////////////////////////////////////////////////

int main( const int argc , const char ** argv ) {
    initializeSsl();
    if( controllerRequested(argc,argv) )
        startController(argc,argv);
    else
    if( serverRequested(argc,argv) )
        startServer(argc,argv);
    else
    if( clientRequested(argc,argv) )
        startClient(argc,argv);
    else
        usage();
    cleanupSsl();
    cleanupLogger();

    return ( 0 );
}

void startController( const int argc , const char ** argv ) {
    ControllerApplication application(argc,argv);

    application.run();
}

void startClient( const int argc , const char ** argv ) {
    ClientApplication application(argc,argv);

    application.run();
}

void startServer( const int argc , const char ** argv ) {
    ServerApplication application(argc,argv);

    application.run();
}

bool serverRequested( const int argc , const char ** argv ) {
    return ( flagSpecified(argc,argv,kFlagServer) );
}

bool clientRequested( const int argc , const char ** argv ) {
    return ( flagSpecified(argc,argv,kFlagClient) );
}

bool controllerRequested( const int argc , const char ** argv ) {
    return ( flagSpecified(argc,argv,kFlagController) );
}

void usage( void ) {
    std::cout << kVersion << std::endl;
    std::cout << "Basic usage: " << std::endl;
    std::cout << "Run as server: ias --server --config <path>" << std::endl;
    std::cout << "Run as controller: ias --controller --config <path>" << std::endl;
    std::cout << "Run as client: ias --client [options]" << std::endl;
    std::cout << "Run as eventstream: ias --eventstream --key <API key>" << std::endl;
    std::cout << std::endl;
    std::cout << "Options:" << std::endl;
    std::cout << " --address [hostname]" << std::endl;
}

void initializeSsl( void ) {
    SSL_load_error_strings();
    SSL_library_init();
    OpenSSL_add_all_algorithms();
}

void cleanupSsl( void ) {
    CONF_modules_free();
    ERR_remove_state(0);
    ENGINE_cleanup();
    CONF_modules_unload(1);
    ERR_free_strings();
    EVP_cleanup();
    CRYPTO_cleanup_all_ex_data();
}

void cleanupLogger( void ) {
    Logger::cleanup();
}
<commit_msg>Modify options of usage function.<commit_after>/**
 * A set of functions and method which assist the main function to set up
 * the requested feature of the Intelligent Automation System.
 *
 * @date                    Jul 2, 2014
 * @author                  Joeri HERMANS
 * @version                 0.1
 *
 * Copyright 2013 Joeri HERMANS
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// BEGIN Includes. ///////////////////////////////////////////////////

// System dependencies.
#include <cassert>
#include <cstring>
#include <string>
#include <iostream>
#include <openssl/conf.h>
#include <openssl/engine.h>
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

// Application dependencies.
#include <ias/application/constants.h>
#include <ias/application/client/client_application.h>
#include <ias/application/controller_application.h>
#include <ias/application/server_application.h>
#include <ias/main.h>
#include <ias/util/util.h>
#include <ias/logger/logger.h>

// END Includes. /////////////////////////////////////////////////////

int main( const int argc , const char ** argv ) {
    initializeSsl();
    if( controllerRequested(argc,argv) )
        startController(argc,argv);
    else
    if( serverRequested(argc,argv) )
        startServer(argc,argv);
    else
    if( clientRequested(argc,argv) )
        startClient(argc,argv);
    else
        usage();
    cleanupSsl();
    cleanupLogger();

    return ( 0 );
}

void startController( const int argc , const char ** argv ) {
    ControllerApplication application(argc,argv);

    application.run();
}

void startClient( const int argc , const char ** argv ) {
    ClientApplication application(argc,argv);

    application.run();
}

void startServer( const int argc , const char ** argv ) {
    ServerApplication application(argc,argv);

    application.run();
}

bool serverRequested( const int argc , const char ** argv ) {
    return ( flagSpecified(argc,argv,kFlagServer) );
}

bool clientRequested( const int argc , const char ** argv ) {
    return ( flagSpecified(argc,argv,kFlagClient) );
}

bool controllerRequested( const int argc , const char ** argv ) {
    return ( flagSpecified(argc,argv,kFlagController) );
}

void usage( void ) {
    std::cout << kVersion << std::endl;
    std::cout << "Basic usage: " << std::endl;
    std::cout << "Run as server: ias --server --config <path>" << std::endl;
    std::cout << "Run as controller: ias --controller --config <path>" << std::endl;
    std::cout << "Run as client: ias --client [options]" << std::endl;
    std::cout << "Run as eventstream: ias --eventstream --key <API key> [options]" << std::endl;
    std::cout << std::endl;
    std::cout << "Options:" << std::endl;
    std::cout << " --address [hostname]" << std::endl;
    std::cout << " --ssl" << std::endl;
}

void initializeSsl( void ) {
    SSL_load_error_strings();
    SSL_library_init();
    OpenSSL_add_all_algorithms();
}

void cleanupSsl( void ) {
    CONF_modules_free();
    ERR_remove_state(0);
    ENGINE_cleanup();
    CONF_modules_unload(1);
    ERR_free_strings();
    EVP_cleanup();
    CRYPTO_cleanup_all_ex_data();
}

void cleanupLogger( void ) {
    Logger::cleanup();
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 tildearrow
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 *The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
#ifdef _WIN32
#define FONT "C:\\Windows\\Fonts\\segoeui.ttf"
#elif __APPLE__
#define FONT "/System/Library/Fonts/SFNSDisplay-Regular.otf"
#elif __linux__
#define FONT "/usr/share/fonts/TTF/Ubuntu-R.ttf"
#else
#warning "really? please tell me if you are compiling on this OS"
#endif

#include "includes.h"
#include "font.h"
#include "ui.h"
#include "gfxeditor.h"
SDL_Window* mainWindow;
SDL_Renderer* mainRenderer;
SDL_Event* event;
int mouseX;
int mouseY;
unsigned int mouseB;
unsigned int mouseBold;
SDL_Color color[16];
bool willquit;
uisystem* ui;
gfxeditor* geditor;
font* mainFont;
int curview;
int cureditid, curedittype;
const char* viewname[9]={"Graphics","Audio","Entity Types","Scenes","Functions","ShouldNotAppear","ShouldNotAppear","ShouldNotAppear","ShouldNotAppear"};

struct graphic {
  string name;
  int id;
  int width;
  int height;
  int originX, originY;
  int subgraphics;
  bool background;
  unsigned char** data;
  int colmode;
  unsigned char** colmask;
};

struct audio {
  string name;
  int id;
  int size;
  float* data;
  int finaltype;
};

struct etype {
  string name;
  int id;
  int initialgraphic;
  int initialsubgraphic;
  int parent;
  int category;
  std::vector<string> eventcode;
  string headercode;
};

struct viewport {
  SDL_Rect view, port;
  float viewangle, portangle;
};

struct scene {
  string name;
  int id;
  int width;
  int height;
  bool freeze;
  std::vector<viewport> viewports;
};

struct function {
  string name;
  int id;
  string code;
};

std::vector<graphic> graphics;
std::vector<audio> sounds;
std::vector<etype> etypes;
std::vector<scene> scenes;
std::vector<function> functions;

void doNothing(){
  printf("hello world!\n");
}

void drawScreen() {
  SDL_RenderDrawLine(mainRenderer,0,32,1024,32);
  if (curview<5) {
    SDL_RenderDrawLine(mainRenderer,256,32,256,600);
    SDL_RenderDrawLine(mainRenderer,0,53,256,53);
    mainFont->drawf(128,41,color[0],1,1,"%s List",viewname[curview]);
    switch (curview) {
      case 0:
        for (int i=0; i<graphics.size(); i++) {
          mainFont->draw(0,64+(i*20),((cureditid==i && curedittype==0)?(color[1]):(color[0])),0,0,false,graphics[i].name);
        }
        // also draw graphic editor
        geditor->draw();
        break;
      case 1:
        for (int i=0; i<sounds.size(); i++) {
          mainFont->draw(0,64+(i*20),((cureditid==i && curedittype==1)?(color[1]):(color[0])),0,0,false,sounds[i].name);
        }
        break;
      case 2:
        for (int i=0; i<etypes.size(); i++) {
          mainFont->draw(0,64+(i*20),((cureditid==i && curedittype==2)?(color[1]):(color[0])),0,0,false,etypes[i].name);
        }
        break;
      case 3:
        for (int i=0; i<scenes.size(); i++) {
          mainFont->draw(0,64+(i*20),((cureditid==i && curedittype==3)?(color[1]):(color[0])),0,0,false,scenes[i].name);
        }
        break;
      case 4:
        for (int i=0; i<functions.size(); i++) {
          mainFont->draw(0,64+(i*20),((cureditid==i && curedittype==4)?(color[1]):(color[0])),0,0,false, functions[i].name);
        }
        break;
    }
  }
}

void goGraphicsView() {
  curview=0;
}

void goAudioView() {
  curview=1;
}

void goETypesView() {
  curview=2;
}

void goScenesView() {
  curview=3;
}

void goFunctionsView() {
  curview=4;
}

void goProjectView() {
  curview=5;
}

void goSettingsView() {
  curview=6;
}

void goHelpView() {
  curview=7;
}

void goAboutView() {
  curview=8;
}

void handleMouse() {
  if ((mouseB&1)>(mouseBold&1)) { // checks for mouse left pressed
    if (mouseX<256 && mouseY>64) {
      cureditid=(mouseY-64)/20;
      curedittype=curview;
    }
  }
}

void makeNewResource() {
  // make new resource
  int formersize;
  switch (curview) {
    case 0:
      formersize=graphics.size();
      graphics.resize(formersize+1);
      graphics[formersize].id=formersize;
      graphics[formersize].name="graphic";
      graphics[formersize].name+=std::to_string(formersize);
      break;
    case 1:
      formersize=sounds.size();
      sounds.resize(formersize+1);
      sounds[formersize].id=formersize;
      sounds[formersize].name="sound";
      sounds[formersize].name+=std::to_string(formersize);
      break;
    case 2:
      formersize=etypes.size();
      etypes.resize(formersize+1);
      etypes[formersize].id=formersize;
      etypes[formersize].name="type";
      etypes[formersize].name+=std::to_string(formersize);
      break;
    case 3:
      formersize=scenes.size();
      scenes.resize(formersize+1);
      scenes[formersize].id=formersize;
      scenes[formersize].name="scene";
      scenes[formersize].name+=std::to_string(formersize);
      break;
    case 4:
      formersize=functions.size();
      functions.resize(formersize+1);
      functions[formersize].id=formersize;
      functions[formersize].name="func";
      functions[formersize].name+=std::to_string(formersize);
      break;
  }
}

int main() {
  willquit=false;
  // init everything
  SDL_Init(SDL_INIT_VIDEO);
  TTF_Init();
  ui=new uisystem;
  event=new SDL_Event;
  string title;
  title="LowerTriad";
  mainWindow=SDL_CreateWindow(title.c_str(),0,0,1024,600,SDL_WINDOW_RESIZABLE);
  if (!mainWindow) {
    printf("i'm sorry, but window can't be created: %s\n",SDL_GetError());
    return 1;
  }
  mainRenderer=SDL_CreateRenderer(mainWindow,-1,SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC);
  // initialize UI
  mainFont=new font;
  mainFont->setrenderer(mainRenderer);
  if (!mainFont->load(FONT,14)) {
    printf("can't load font, which means this application is going to crash now...\n");
  }
  ui->setrenderer(mainRenderer);
  color[0].r=192; color[0].g=192; color[0].b=192; color[0].a=255; // main
  color[1].r=255; color[1].g=255; color[1].b=255; color[1].a=255; // alternate
  color[2].r=0;   color[2].g=255; color[2].b=0;   color[2].a=255; // success
  color[3].r=255; color[3].g=255; color[3].b=0;   color[3].a=255; // ongoing
  color[4].r=255; color[4].g=0;   color[4].b=0;   color[4].a=255; // failure
  ui->setfont(mainFont);
  ui->addbutton(0,0,48,22,"Prepare","Prepare CMake project",color[0],color[0],doNothing);
  ui->addbutton(48,0,40,22,"Build","Build game",color[0],color[0],doNothing);
  ui->addbutton(100,0,32,22,"Run","Run compiled game",color[0],color[0],doNothing);
  ui->addbutton(132,0,56,22,"Package","Create package",color[0],color[0],doNothing);

  ui->addbutton(200,0,64,22,"Graphics","",color[0],color[0],goGraphicsView);
  ui->addbutton(264,0,50,22,"Audio","Sound/Music",color[0],color[0],goAudioView);
  ui->addbutton(314,0,80,22,"EntityTypes","",color[0],color[0],goETypesView);
  ui->addbutton(394,0,50,22,"Scenes","",color[0],color[0],goScenesView);
  ui->addbutton(444,0,72,22,"Functions","",color[0],color[0],goFunctionsView);
  ui->addbutton(516,0,60,22,"Project","",color[0],color[0],goProjectView);

  ui->addbutton(1024-160,0,60,22,"Settings","",color[0],color[0],goSettingsView);
  ui->addbutton(1024-100,0,50,22,"Help","",color[0],color[0],goHelpView);
  ui->addbutton(1024-50,0,50,22,"About","",color[0],color[0],goAboutView);

  ui->addbutton(225,32,32,22,"Add","Add a new resource",color[0],color[0],makeNewResource);

  ui->setmouse(&mouseX,&mouseY,&mouseB,&mouseBold);
  // initialize graphic editor
  geditor=new gfxeditor;
  geditor->setfont(mainFont);
  // initialize IDE variables
  cureditid=-1; curedittype=0; curview=0;
  while (1) {
    // check events
    while (SDL_PollEvent(event)) {
      if (event->type==SDL_QUIT) {
        willquit=true;
      }
    }
    SDL_SetRenderDrawColor(mainRenderer,0,0,0,0);
    SDL_RenderClear(mainRenderer);
    SDL_SetRenderDrawColor(mainRenderer,color[0].r,color[0].g,color[0].b,color[0].a);
    mouseBold=mouseB;
    mouseB=SDL_GetMouseState(&mouseX, &mouseY);
    handleMouse();
    drawScreen();
    ui->drawall();
    SDL_RenderPresent(mainRenderer);
    if (willquit) {
      break;
    }
  }
  return 0;
}
<commit_msg>more graphic editor stuff<commit_after>/*
 * Copyright (c) 2016 tildearrow
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 *The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
#ifdef _WIN32
#define FONT "C:\\Windows\\Fonts\\segoeui.ttf"
#elif __APPLE__
#define FONT "/System/Library/Fonts/SFNSDisplay-Regular.otf"
#elif __linux__
#define FONT "/usr/share/fonts/TTF/Ubuntu-R.ttf"
#else
#warning "really? please tell me if you are compiling on this OS"
#endif

#include "includes.h"
#include "font.h"
#include "ui.h"
#include "gfxeditor.h"
SDL_Window* mainWindow;
SDL_Renderer* mainRenderer;
SDL_Event* event;
int mouseX;
int mouseY;
unsigned int mouseB;
unsigned int mouseBold;
SDL_Color color[16];
bool willquit;
uisystem* ui;
gfxeditor* geditor;
font* mainFont;
int curview;
int cureditid, curedittype;
const char* viewname[9]={"Graphics","Audio","Entity Types","Scenes","Functions","ShouldNotAppear","ShouldNotAppear","ShouldNotAppear","ShouldNotAppear"};

struct graphic {
  string name;
  int id;
  int width;
  int height;
  int originX, originY;
  int subgraphics;
  bool background;
  std::vector<unsigned char*> data;
  int colmode;
  unsigned char** colmask;
};

struct audio {
  string name;
  int id;
  int size;
  float* data;
  int finaltype;
};

struct etype {
  string name;
  int id;
  int initialgraphic;
  int initialsubgraphic;
  int parent;
  int category;
  std::vector<string> eventcode;
  string headercode;
};

struct viewport {
  SDL_Rect view, port;
  float viewangle, portangle;
};

struct scene {
  string name;
  int id;
  int width;
  int height;
  bool freeze;
  std::vector<viewport> viewports;
};

struct function {
  string name;
  int id;
  string code;
};

std::vector<graphic> graphics;
std::vector<audio> sounds;
std::vector<etype> etypes;
std::vector<scene> scenes;
std::vector<function> functions;

void doNothing(){
  printf("hello world!\n");
}

void drawScreen() {
  SDL_RenderDrawLine(mainRenderer,0,32,1024,32);
  if (curview<5) {
    SDL_RenderDrawLine(mainRenderer,256,32,256,600);
    SDL_RenderDrawLine(mainRenderer,0,53,256,53);
    mainFont->drawf(128,41,color[0],1,1,"%s List",viewname[curview]);
    switch (curview) {
      case 0:
        for (int i=0; i<graphics.size(); i++) {
          mainFont->draw(0,64+(i*20),((cureditid==i && curedittype==0)?(color[1]):(color[0])),0,0,false,graphics[i].name);
        }
        // also draw graphic editor
        geditor->draw();
        break;
      case 1:
        for (int i=0; i<sounds.size(); i++) {
          mainFont->draw(0,64+(i*20),((cureditid==i && curedittype==1)?(color[1]):(color[0])),0,0,false,sounds[i].name);
        }
        break;
      case 2:
        for (int i=0; i<etypes.size(); i++) {
          mainFont->draw(0,64+(i*20),((cureditid==i && curedittype==2)?(color[1]):(color[0])),0,0,false,etypes[i].name);
        }
        break;
      case 3:
        for (int i=0; i<scenes.size(); i++) {
          mainFont->draw(0,64+(i*20),((cureditid==i && curedittype==3)?(color[1]):(color[0])),0,0,false,scenes[i].name);
        }
        break;
      case 4:
        for (int i=0; i<functions.size(); i++) {
          mainFont->draw(0,64+(i*20),((cureditid==i && curedittype==4)?(color[1]):(color[0])),0,0,false, functions[i].name);
        }
        break;
    }
  }
}

void goGraphicsView() {
  curview=0;
}

void goAudioView() {
  curview=1;
}

void goETypesView() {
  curview=2;
}

void goScenesView() {
  curview=3;
}

void goFunctionsView() {
  curview=4;
}

void goProjectView() {
  curview=5;
}

void goSettingsView() {
  curview=6;
}

void goHelpView() {
  curview=7;
}

void goAboutView() {
  curview=8;
}

void handleMouse() {
  if ((mouseB&1)>(mouseBold&1)) { // checks for mouse left pressed
    if (mouseX<256 && mouseY>64) {
      cureditid=(mouseY-64)/20;
      curedittype=curview;
      switch (curview) {
        case 0: geditor->setdata(graphics[cureditid].data[0], graphics[cureditid].width, graphics[cureditid].height); break;
      }
    }
  }
}

void makeNewResource() {
  // make new resource
  int formersize;
  switch (curview) {
    case 0:
      formersize=graphics.size();
      graphics.resize(formersize+1);
      graphics[formersize].id=formersize;
      graphics[formersize].name="graphic";
      graphics[formersize].name+=std::to_string(formersize);
      // create pre-defined graphic
      graphics[formersize].subgraphics=1;
      graphics[formersize].width=32;
      graphics[formersize].height=32;
      graphics[formersize].data.resize(1);
      graphics[formersize].data[0]=new unsigned char[4096];
      break;
    case 1:
      formersize=sounds.size();
      sounds.resize(formersize+1);
      sounds[formersize].id=formersize;
      sounds[formersize].name="sound";
      sounds[formersize].name+=std::to_string(formersize);
      break;
    case 2:
      formersize=etypes.size();
      etypes.resize(formersize+1);
      etypes[formersize].id=formersize;
      etypes[formersize].name="type";
      etypes[formersize].name+=std::to_string(formersize);
      break;
    case 3:
      formersize=scenes.size();
      scenes.resize(formersize+1);
      scenes[formersize].id=formersize;
      scenes[formersize].name="scene";
      scenes[formersize].name+=std::to_string(formersize);
      break;
    case 4:
      formersize=functions.size();
      functions.resize(formersize+1);
      functions[formersize].id=formersize;
      functions[formersize].name="func";
      functions[formersize].name+=std::to_string(formersize);
      break;
  }
}

int main() {
  willquit=false;
  // init everything
  SDL_Init(SDL_INIT_VIDEO);
  TTF_Init();
  ui=new uisystem;
  event=new SDL_Event;
  string title;
  title="LowerTriad";
  mainWindow=SDL_CreateWindow(title.c_str(),0,0,1024,600,SDL_WINDOW_RESIZABLE);
  if (!mainWindow) {
    printf("i'm sorry, but window can't be created: %s\n",SDL_GetError());
    return 1;
  }
  mainRenderer=SDL_CreateRenderer(mainWindow,-1,SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC);
  // initialize UI
  mainFont=new font;
  mainFont->setrenderer(mainRenderer);
  if (!mainFont->load(FONT,14)) {
    printf("can't load font, which means this application is going to crash now...\n");
  }
  ui->setrenderer(mainRenderer);
  color[0].r=192; color[0].g=192; color[0].b=192; color[0].a=255; // main
  color[1].r=255; color[1].g=255; color[1].b=255; color[1].a=255; // alternate
  color[2].r=0;   color[2].g=255; color[2].b=0;   color[2].a=255; // success
  color[3].r=255; color[3].g=255; color[3].b=0;   color[3].a=255; // ongoing
  color[4].r=255; color[4].g=0;   color[4].b=0;   color[4].a=255; // failure
  ui->setfont(mainFont);
  ui->addbutton(0,0,48,22,"Prepare","Prepare CMake project",color[0],color[0],doNothing);
  ui->addbutton(48,0,40,22,"Build","Build game",color[0],color[0],doNothing);
  ui->addbutton(100,0,32,22,"Run","Run compiled game",color[0],color[0],doNothing);
  ui->addbutton(132,0,56,22,"Package","Create package",color[0],color[0],doNothing);

  ui->addbutton(200,0,64,22,"Graphics","",color[0],color[0],goGraphicsView);
  ui->addbutton(264,0,50,22,"Audio","Sound/Music",color[0],color[0],goAudioView);
  ui->addbutton(314,0,80,22,"EntityTypes","",color[0],color[0],goETypesView);
  ui->addbutton(394,0,50,22,"Scenes","",color[0],color[0],goScenesView);
  ui->addbutton(444,0,72,22,"Functions","",color[0],color[0],goFunctionsView);
  ui->addbutton(516,0,60,22,"Project","",color[0],color[0],goProjectView);

  ui->addbutton(1024-160,0,60,22,"Settings","",color[0],color[0],goSettingsView);
  ui->addbutton(1024-100,0,50,22,"Help","",color[0],color[0],goHelpView);
  ui->addbutton(1024-50,0,50,22,"About","",color[0],color[0],goAboutView);

  ui->addbutton(225,32,32,22,"Add","Add a new resource",color[0],color[0],makeNewResource);

  ui->setmouse(&mouseX,&mouseY,&mouseB,&mouseBold);
  // initialize graphic editor
  geditor=new gfxeditor;
  geditor->setfont(mainFont);
  // initialize IDE variables
  cureditid=-1; curedittype=0; curview=0;
  while (1) {
    // check events
    while (SDL_PollEvent(event)) {
      if (event->type==SDL_QUIT) {
        willquit=true;
      }
    }
    SDL_SetRenderDrawColor(mainRenderer,0,0,0,0);
    SDL_RenderClear(mainRenderer);
    SDL_SetRenderDrawColor(mainRenderer,color[0].r,color[0].g,color[0].b,color[0].a);
    mouseBold=mouseB;
    mouseB=SDL_GetMouseState(&mouseX, &mouseY);
    handleMouse();
    drawScreen();
    ui->drawall();
    SDL_RenderPresent(mainRenderer);
    if (willquit) {
      break;
    }
  }
  return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2018 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "Output.hxx"
#include "Error.hxx"
#include "event/SocketEvent.hxx"
#include "event/TimerEvent.hxx"
#include "direct.hxx"
#include "io/Splice.hxx"
#include "io/FileDescriptor.hxx"
#include "system/Error.hxx"
#include "istream/Bucket.hxx"
#include "istream/Handler.hxx"
#include "istream/Pointer.hxx"
#include "istream/UnusedPtr.hxx"
#include "pool/pool.hxx"
#include "util/StaticArray.hxx"

#include <was/protocol.h>

#include <sys/uio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

static constexpr Event::Duration was_output_timeout = std::chrono::minutes(2);

class WasOutput final : IstreamHandler {
public:
    FileDescriptor fd;
    SocketEvent event;
    TimerEvent timeout_event;

    WasOutputHandler &handler;

    IstreamPointer input;

    uint64_t sent = 0;

    bool known_length = false;

    WasOutput(EventLoop &event_loop, FileDescriptor _fd,
              UnusedIstreamPtr _input,
              WasOutputHandler &_handler)
        :fd(_fd),
         event(event_loop, BIND_THIS_METHOD(WriteEventCallback),
               SocketDescriptor::FromFileDescriptor(fd)),
         timeout_event(event_loop, BIND_THIS_METHOD(OnTimeout)),
         handler(_handler),
         input(std::move(_input), *this, ISTREAM_TO_PIPE) {
        ScheduleWrite();
    }

    void ScheduleWrite() {
        event.ScheduleWrite();
        timeout_event.Schedule(was_output_timeout);
    }

    void AbortError(std::exception_ptr ep) {
        event.Cancel();
        timeout_event.Cancel();

        if (input.IsDefined())
            input.ClearAndClose();

        handler.WasOutputError(ep);
    }

    bool CheckLength();

    void WriteEventCallback(unsigned events) noexcept;

    void OnTimeout() noexcept {
        AbortError(std::make_exception_ptr(WasError("send timeout")));
    }

    /* virtual methods from class IstreamHandler */
    bool OnIstreamReady() noexcept override;
    size_t OnData(const void *data, size_t length) noexcept override;
    ssize_t OnDirect(FdType type, int fd, size_t max_length) noexcept override;
    void OnEof() noexcept override;
    void OnError(std::exception_ptr ep) noexcept override;
};

bool
WasOutput::CheckLength()
{
    if (known_length)
        return true;

    off_t available = input.GetAvailable(false);
    if (available < 0)
        return true;

    known_length = true;
    return handler.WasOutputLength(sent + available);
}

/*
 * libevent callback
 *
 */

inline void
WasOutput::WriteEventCallback(unsigned) noexcept
{
    assert(fd.IsDefined());
    assert(input.IsDefined());

    event.CancelWrite();
    timeout_event.Cancel();

    if (CheckLength())
        input.Read();
}

/*
 * istream handler for the request
 *
 */

bool
WasOutput::OnIstreamReady() noexcept
{
    assert(fd.IsDefined());
    assert(input.IsDefined());

    /* collect buckets */

    IstreamBucketList list;

    try {
        input.FillBucketList(list);
    } catch (...) {
        input.Clear();
        AbortError(std::current_exception());
        return false;
    }

    if (list.IsEmpty() && !list.HasMore()) {
        /* our input has ended */

        input.ClearAndClose();
        event.Cancel();
        timeout_event.Cancel();

        if (!known_length && !handler.WasOutputLength(sent))
            return false;

        handler.WasOutputEof();
        return false;
    }

    /* convert buckets to struct iovec array */

    StaticArray<struct iovec, 64> v;
    bool more = list.HasMore(), result = false;
    size_t total = 0;

    for (const auto &i : list) {
        if (i.GetType() != IstreamBucket::Type::BUFFER) {
            result = true;
            more = true;
            break;
        }

        if (v.full()) {
            more = true;
            break;
        }

        const auto buffer = i.GetBuffer();

        auto &w = v.append();
        w.iov_base = const_cast<void *>(buffer.data);
        w.iov_len = buffer.size;
        total += buffer.size;
    }

    if (v.empty())
        return true;

    /* write this struct iovec array */

    ssize_t nbytes = writev(fd.Get(), &v.front(), v.size());
    if (nbytes < 0) {
        int e = errno;
        if (e == EAGAIN) {
            ScheduleWrite();
            return false;
        }

        AbortError(std::make_exception_ptr(MakeErrno("Write to WAS process failed")));
        return false;
    }

    input.ConsumeBucketList(nbytes);

    if (!more && size_t(nbytes) == total) {
        /* we've just reached end of our input */

        input.ClearAndClose();
        event.Cancel();
        timeout_event.Cancel();

        if (!known_length && !handler.WasOutputLength(sent))
            return false;

        handler.WasOutputEof();
        return false;
    }

    return result;
}

inline size_t
WasOutput::OnData(const void *p, size_t length) noexcept
{
    assert(fd.IsDefined());
    assert(input.IsDefined());

    ssize_t nbytes = fd.Write(p, length);
    if (gcc_likely(nbytes > 0)) {
        sent += nbytes;
        ScheduleWrite();
    } else if (nbytes < 0) {
        if (errno == EAGAIN) {
            ScheduleWrite();
            return 0;
        }

        AbortError(std::make_exception_ptr(MakeErrno("Write to WAS process failed")));
        return 0;
    }

    return (size_t)nbytes;
}

inline ssize_t
WasOutput::OnDirect(gcc_unused FdType type, int source_fd, size_t max_length) noexcept
{
    assert(fd.IsDefined());

    ssize_t nbytes = SpliceToPipe(source_fd, fd.Get(), max_length);
    if (gcc_likely(nbytes > 0)) {
        sent += nbytes;
        ScheduleWrite();
    } else if (nbytes < 0 && errno == EAGAIN) {
        if (!fd.IsReadyForWriting()) {
            ScheduleWrite();
            return ISTREAM_RESULT_BLOCKING;
        }

        /* try again, just in case fd has become ready between
           the first istream_direct_to_pipe() call and
           fd.IsReadyForWriting() */
        nbytes = SpliceToPipe(source_fd, fd.Get(), max_length);
    }

    return nbytes;
}

void
WasOutput::OnEof() noexcept
{
    assert(input.IsDefined());

    input.Clear();
    event.Cancel();
    timeout_event.Cancel();

    if (!known_length && !handler.WasOutputLength(sent))
        return;

    handler.WasOutputEof();
}

void
WasOutput::OnError(std::exception_ptr ep) noexcept
{
    assert(input.IsDefined());

    input.Clear();
    event.Cancel();
    timeout_event.Cancel();

    handler.WasOutputPremature(sent, ep);
}

/*
 * constructor
 *
 */

WasOutput *
was_output_new(struct pool &pool, EventLoop &event_loop,
               FileDescriptor fd, UnusedIstreamPtr input,
               WasOutputHandler &handler)
{
    assert(fd.IsDefined());

    return NewFromPool<WasOutput>(pool, event_loop, fd,
                                  std::move(input), handler);
}

uint64_t
was_output_free(WasOutput *output)
{
    assert(output != nullptr);

    if (output->input.IsDefined())
        output->input.ClearAndClose();

    output->event.Cancel();
    output->timeout_event.Cancel();

    return output->sent;
}

bool
was_output_check_length(WasOutput &output)
{
    return output.CheckLength();
}
<commit_msg>was/Output: call destructor<commit_after>/*
 * Copyright 2007-2018 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "Output.hxx"
#include "Error.hxx"
#include "event/SocketEvent.hxx"
#include "event/TimerEvent.hxx"
#include "direct.hxx"
#include "io/Splice.hxx"
#include "io/FileDescriptor.hxx"
#include "system/Error.hxx"
#include "istream/Bucket.hxx"
#include "istream/Handler.hxx"
#include "istream/Pointer.hxx"
#include "istream/UnusedPtr.hxx"
#include "pool/pool.hxx"
#include "util/StaticArray.hxx"

#include <was/protocol.h>

#include <sys/uio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

static constexpr Event::Duration was_output_timeout = std::chrono::minutes(2);

class WasOutput final : IstreamHandler {
public:
    FileDescriptor fd;
    SocketEvent event;
    TimerEvent timeout_event;

    WasOutputHandler &handler;

    IstreamPointer input;

    uint64_t sent = 0;

    bool known_length = false;

    WasOutput(EventLoop &event_loop, FileDescriptor _fd,
              UnusedIstreamPtr _input,
              WasOutputHandler &_handler)
        :fd(_fd),
         event(event_loop, BIND_THIS_METHOD(WriteEventCallback),
               SocketDescriptor::FromFileDescriptor(fd)),
         timeout_event(event_loop, BIND_THIS_METHOD(OnTimeout)),
         handler(_handler),
         input(std::move(_input), *this, ISTREAM_TO_PIPE) {
        ScheduleWrite();
    }

    void Destroy() noexcept {
        this->~WasOutput();
    }

    void DestroyEof() noexcept {
        auto &_handler = handler;
        Destroy();
        _handler.WasOutputEof();
    }

    void DestroyPremature(std::exception_ptr ep) noexcept {
        const auto _sent = sent;
        auto &_handler = handler;
        Destroy();
        _handler.WasOutputPremature(_sent, ep);
    }

    void DestroyError(std::exception_ptr ep) noexcept {
        auto &_handler = handler;
        Destroy();
        _handler.WasOutputError(ep);
    }

    void ScheduleWrite() {
        event.ScheduleWrite();
        timeout_event.Schedule(was_output_timeout);
    }

    void AbortError(std::exception_ptr ep) {
        if (input.IsDefined())
            input.ClearAndClose();

        DestroyError(ep);
    }

    bool CheckLength();

    void WriteEventCallback(unsigned events) noexcept;

    void OnTimeout() noexcept {
        AbortError(std::make_exception_ptr(WasError("send timeout")));
    }

    /* virtual methods from class IstreamHandler */
    bool OnIstreamReady() noexcept override;
    size_t OnData(const void *data, size_t length) noexcept override;
    ssize_t OnDirect(FdType type, int fd, size_t max_length) noexcept override;
    void OnEof() noexcept override;
    void OnError(std::exception_ptr ep) noexcept override;
};

bool
WasOutput::CheckLength()
{
    if (known_length)
        return true;

    off_t available = input.GetAvailable(false);
    if (available < 0)
        return true;

    known_length = true;
    return handler.WasOutputLength(sent + available);
}

/*
 * libevent callback
 *
 */

inline void
WasOutput::WriteEventCallback(unsigned) noexcept
{
    assert(fd.IsDefined());
    assert(input.IsDefined());

    event.CancelWrite();
    timeout_event.Cancel();

    if (CheckLength())
        input.Read();
}

/*
 * istream handler for the request
 *
 */

bool
WasOutput::OnIstreamReady() noexcept
{
    assert(fd.IsDefined());
    assert(input.IsDefined());

    /* collect buckets */

    IstreamBucketList list;

    try {
        input.FillBucketList(list);
    } catch (...) {
        input.Clear();
        AbortError(std::current_exception());
        return false;
    }

    if (list.IsEmpty() && !list.HasMore()) {
        /* our input has ended */

        input.ClearAndClose();
        event.Cancel();
        timeout_event.Cancel();

        if (!known_length && !handler.WasOutputLength(sent))
            return false;

        DestroyEof();
        return false;
    }

    /* convert buckets to struct iovec array */

    StaticArray<struct iovec, 64> v;
    bool more = list.HasMore(), result = false;
    size_t total = 0;

    for (const auto &i : list) {
        if (i.GetType() != IstreamBucket::Type::BUFFER) {
            result = true;
            more = true;
            break;
        }

        if (v.full()) {
            more = true;
            break;
        }

        const auto buffer = i.GetBuffer();

        auto &w = v.append();
        w.iov_base = const_cast<void *>(buffer.data);
        w.iov_len = buffer.size;
        total += buffer.size;
    }

    if (v.empty())
        return true;

    /* write this struct iovec array */

    ssize_t nbytes = writev(fd.Get(), &v.front(), v.size());
    if (nbytes < 0) {
        int e = errno;
        if (e == EAGAIN) {
            ScheduleWrite();
            return false;
        }

        AbortError(std::make_exception_ptr(MakeErrno("Write to WAS process failed")));
        return false;
    }

    input.ConsumeBucketList(nbytes);

    if (!more && size_t(nbytes) == total) {
        /* we've just reached end of our input */

        input.ClearAndClose();
        event.Cancel();
        timeout_event.Cancel();

        if (!known_length && !handler.WasOutputLength(sent))
            return false;

        DestroyEof();
        return false;
    }

    return result;
}

inline size_t
WasOutput::OnData(const void *p, size_t length) noexcept
{
    assert(fd.IsDefined());
    assert(input.IsDefined());

    ssize_t nbytes = fd.Write(p, length);
    if (gcc_likely(nbytes > 0)) {
        sent += nbytes;
        ScheduleWrite();
    } else if (nbytes < 0) {
        if (errno == EAGAIN) {
            ScheduleWrite();
            return 0;
        }

        AbortError(std::make_exception_ptr(MakeErrno("Write to WAS process failed")));
        return 0;
    }

    return (size_t)nbytes;
}

inline ssize_t
WasOutput::OnDirect(gcc_unused FdType type, int source_fd, size_t max_length) noexcept
{
    assert(fd.IsDefined());

    ssize_t nbytes = SpliceToPipe(source_fd, fd.Get(), max_length);
    if (gcc_likely(nbytes > 0)) {
        sent += nbytes;
        ScheduleWrite();
    } else if (nbytes < 0 && errno == EAGAIN) {
        if (!fd.IsReadyForWriting()) {
            ScheduleWrite();
            return ISTREAM_RESULT_BLOCKING;
        }

        /* try again, just in case fd has become ready between
           the first istream_direct_to_pipe() call and
           fd.IsReadyForWriting() */
        nbytes = SpliceToPipe(source_fd, fd.Get(), max_length);
    }

    return nbytes;
}

void
WasOutput::OnEof() noexcept
{
    assert(input.IsDefined());

    input.Clear();
    event.Cancel();
    timeout_event.Cancel();

    if (!known_length && !handler.WasOutputLength(sent))
        return;

    DestroyEof();
}

void
WasOutput::OnError(std::exception_ptr ep) noexcept
{
    assert(input.IsDefined());

    input.Clear();

    DestroyPremature(ep);
}

/*
 * constructor
 *
 */

WasOutput *
was_output_new(struct pool &pool, EventLoop &event_loop,
               FileDescriptor fd, UnusedIstreamPtr input,
               WasOutputHandler &handler)
{
    assert(fd.IsDefined());

    return NewFromPool<WasOutput>(pool, event_loop, fd,
                                  std::move(input), handler);
}

uint64_t
was_output_free(WasOutput *output)
{
    assert(output != nullptr);

    if (output->input.IsDefined())
        output->input.ClearAndClose();

    const auto sent = output->sent;
    output->Destroy();
    return sent;
}

bool
was_output_check_length(WasOutput &output)
{
    return output.CheckLength();
}
<|endoftext|>