<commit_before>#define _BSD_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ptrace.h>
#include <sys/uio.h>
#include <unistd.h>
#include "ptbox.h"

pt_debugger::pt_debugger() : on_return_callback(NULL) {}

#if PTBOX_FREEBSD
    bool pt_debugger::use_peekdata = true;
#else
    bool pt_debugger::use_peekdata = false;
#endif

bool has_null(char *buf, unsigned long size) {
    for (unsigned long i = 0; i < size; ++i) {
        if (buf[i] == '\0')
            return true;
    }
    return false;
}

void pt_debugger::set_process(pt_process *proc) {
    process = proc;
}

void pt_debugger::new_process() {
#if PTBOX_FREEBSD
    tid = process->getpid();
#endif
}

#if PTBOX_FREEBSD
void pt_debugger::update_syscall(struct ptrace_lwpinfo *info) {
    struct reg bsd_regs;
    ptrace(PT_GETREGS, tid, (caddr_t) &bsd_regs, 0);
    map_regs_to_linux(&bsd_regs, &bsd_converted_regs);

    if (info->pl_flags & PL_FLAG_SCX)
        bsd_converted_regs.orig_rax = syscall_[info->pl_lwpid];
        // Not available on all kernels.
        // bsd_converted_regs.orig_rax = info->pl_syscall_code;
    else if (info->pl_flags & PL_FLAG_SCE)
        syscall_[info->pl_lwpid] = bsd_converted_regs.rax;
}

void pt_debugger::setpid(pid_t pid) {
    this->tid = pid;
}
#else
void pt_debugger::settid(pid_t tid) {
    this->tid = tid;
    if (!syscall_.count(tid)) syscall_[tid] = 0;
    syscall_[tid] ^= 1;
}
#endif

#ifdef PTBOX_NEED_PRE_POST_SYSCALL
void pt_debugger::pre_syscall() {}
void pt_debugger::post_syscall() {}
#endif

long pt_debugger::peek_reg(int idx) {
#if PTBOX_FREEBSD
    return ((reg_type*)&bsd_converted_regs)[idx];
#else
    long res;
    errno = 0;
    res = ptrace(PTRACE_PEEKUSER, tid, sizeof(long) * idx, 0);
    if (res == -1 && errno)
        perror("ptrace(PTRACE_PEEKUSER)");
    return res;
#endif
}

void pt_debugger::poke_reg(int idx, long data) {
#if PTBOX_FREEBSD
    ((reg_type*)&bsd_converted_regs)[idx] = data;

    struct reg bsd_regs;

    // Update bsd_regs with latest regs, since not all are mapped by map_regs_from_linux and we don't want
    // garbage to be written to the other registers.
    // Alternatively we could be mapping them in map_regs, but that'd be more fragile and less easy (there are
    // some registers, like r_trapno on FreeBSD, that have no real equivalent on Linux, and vice-versa).
    ptrace(PT_GETREGS, tid, (caddr_t) &bsd_regs, 0);

    map_regs_from_linux(&bsd_regs, &bsd_converted_regs);
    ptrace(PT_SETREGS, tid, (caddr_t) &bsd_regs, 0);
#else
    ptrace(PTRACE_POKEUSER, tid, sizeof(long) * idx, data);
#endif
}

#if PTBOX_FREEBSD
typedef int ptrace_read_t;
#else
typedef long ptrace_read_t;

#ifndef SYS_process_vm_readv
#define SYS_process_vm_readv 270
#endif

ssize_t __attribute__((weak)) process_vm_readv(
    pid_t pid, const struct iovec *lvec, unsigned long liovcnt,
    const struct iovec *rvec, unsigned long riovcnt, unsigned long flags
) {
    return syscall(SYS_process_vm_readv, (long) pid, lvec, liovcnt, rvec, riovcnt, flags);
}
#endif

char *pt_debugger::readstr(unsigned long addr, size_t max_size) {
#if PTBOX_FREEBSD
    return readstr_peekdata(addr, max_size);
#else
    static unsigned long page_size = -sysconf(_SC_PAGESIZE);
    static unsigned long page_mask = (unsigned long) page_size;

    char *buf;
    unsigned long remain, read = 0;
    struct iovec local, remote;

    if (use_peekdata)
        return readstr_peekdata(addr, max_size);

    remain = addr - (addr & page_mask);
    buf = (char *) malloc(max_size + 1);

    while (read < max_size) {
        local.iov_base = (void *) (buf + read);
        local.iov_len = remain;
        remote.iov_base = (void *) (addr + read);
        remote.iov_len = remain;

        if (process_vm_readv(tid, &local, 1, &remote, 1, 0) > 0) {
            if (memchr(buf + read, '\0', remain))
                return buf;
            read += remain;
        } else if (errno == ENOSYS || errno == EPERM) {
            perror("process_vm_readv");
            use_peekdata = true;
            free(buf);
            return readstr_peekdata(addr, max_size);
        } else {
            if (errno != EFAULT && errno != EIO)
                perror("process_vm_readv");
            buf[read] = 0;
            return buf;
        }

        remain = page_size < max_size - read ? page_size : max_size - read;
    }
    buf[max_size] = 0;
    return buf;
#endif
}

char *pt_debugger::readstr_peekdata(unsigned long addr, size_t max_size) {
    size_t size = 4096, read = 0;
    char *buf = (char *) malloc(size);
    union {
        ptrace_read_t val;
        char byte[sizeof(ptrace_read_t)];
    } data;

    while (true) {
        if (read + sizeof(ptrace_read_t) > size) {
            if (max_size && size >= max_size) {
                buf[max_size-1] = 0;
                break;
            }

            size += 4096;
            if (max_size && size > max_size)
                size = max_size;

            void *nbuf = realloc(buf, size);
            if (!nbuf) {
                buf[size-4097] = 0;
                break;
            }
            buf = (char *) nbuf;
        }
#if PTBOX_FREEBSD
        // TODO: we could use PT_IO to speed up this entire function by reading chunks rather than byte
        data.val = ptrace(PT_READ_D, tid, (caddr_t) (addr + read), 0);
#else
        errno = 0;
        data.val = ptrace(PTRACE_PEEKDATA, tid, addr + read, NULL);
        if (data.val == -1 && errno)
            perror("ptrace(PTRACE_PEEKDATA)");
#endif
        memcpy(buf + read, data.byte, sizeof(ptrace_read_t));
        if (has_null(data.byte, sizeof(ptrace_read_t)))
            break;
        read += sizeof(ptrace_read_t);
    }
    return buf;
}

void pt_debugger::freestr(char *buf) {
    free(buf);
}

pt_debugger::~pt_debugger() {}
<commit_msg>Stop false reporting zero byte reads; #300<commit_after>#define _BSD_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ptrace.h>
#include <sys/uio.h>
#include <unistd.h>
#include "ptbox.h"

pt_debugger::pt_debugger() : on_return_callback(NULL) {}

#if PTBOX_FREEBSD
    bool pt_debugger::use_peekdata = true;
#else
    bool pt_debugger::use_peekdata = false;
#endif

bool has_null(char *buf, unsigned long size) {
    for (unsigned long i = 0; i < size; ++i) {
        if (buf[i] == '\0')
            return true;
    }
    return false;
}

void pt_debugger::set_process(pt_process *proc) {
    process = proc;
}

void pt_debugger::new_process() {
#if PTBOX_FREEBSD
    tid = process->getpid();
#endif
}

#if PTBOX_FREEBSD
void pt_debugger::update_syscall(struct ptrace_lwpinfo *info) {
    struct reg bsd_regs;
    ptrace(PT_GETREGS, tid, (caddr_t) &bsd_regs, 0);
    map_regs_to_linux(&bsd_regs, &bsd_converted_regs);

    if (info->pl_flags & PL_FLAG_SCX)
        bsd_converted_regs.orig_rax = syscall_[info->pl_lwpid];
        // Not available on all kernels.
        // bsd_converted_regs.orig_rax = info->pl_syscall_code;
    else if (info->pl_flags & PL_FLAG_SCE)
        syscall_[info->pl_lwpid] = bsd_converted_regs.rax;
}

void pt_debugger::setpid(pid_t pid) {
    this->tid = pid;
}
#else
void pt_debugger::settid(pid_t tid) {
    this->tid = tid;
    if (!syscall_.count(tid)) syscall_[tid] = 0;
    syscall_[tid] ^= 1;
}
#endif

#ifdef PTBOX_NEED_PRE_POST_SYSCALL
void pt_debugger::pre_syscall() {}
void pt_debugger::post_syscall() {}
#endif

long pt_debugger::peek_reg(int idx) {
#if PTBOX_FREEBSD
    return ((reg_type*)&bsd_converted_regs)[idx];
#else
    long res;
    errno = 0;
    res = ptrace(PTRACE_PEEKUSER, tid, sizeof(long) * idx, 0);
    if (res == -1 && errno)
        perror("ptrace(PTRACE_PEEKUSER)");
    return res;
#endif
}

void pt_debugger::poke_reg(int idx, long data) {
#if PTBOX_FREEBSD
    ((reg_type*)&bsd_converted_regs)[idx] = data;

    struct reg bsd_regs;

    // Update bsd_regs with latest regs, since not all are mapped by map_regs_from_linux and we don't want
    // garbage to be written to the other registers.
    // Alternatively we could be mapping them in map_regs, but that'd be more fragile and less easy (there are
    // some registers, like r_trapno on FreeBSD, that have no real equivalent on Linux, and vice-versa).
    ptrace(PT_GETREGS, tid, (caddr_t) &bsd_regs, 0);

    map_regs_from_linux(&bsd_regs, &bsd_converted_regs);
    ptrace(PT_SETREGS, tid, (caddr_t) &bsd_regs, 0);
#else
    ptrace(PTRACE_POKEUSER, tid, sizeof(long) * idx, data);
#endif
}

#if PTBOX_FREEBSD
typedef int ptrace_read_t;
#else
typedef long ptrace_read_t;

#ifndef SYS_process_vm_readv
#define SYS_process_vm_readv 270
#endif

ssize_t __attribute__((weak)) process_vm_readv(
    pid_t pid, const struct iovec *lvec, unsigned long liovcnt,
    const struct iovec *rvec, unsigned long riovcnt, unsigned long flags
) {
    return syscall(SYS_process_vm_readv, (long) pid, lvec, liovcnt, rvec, riovcnt, flags);
}
#endif

char *pt_debugger::readstr(unsigned long addr, size_t max_size) {
#if PTBOX_FREEBSD
    return readstr_peekdata(addr, max_size);
#else
    static unsigned long page_size = -sysconf(_SC_PAGESIZE);
    static unsigned long page_mask = (unsigned long) page_size;

    char *buf;
    unsigned long remain, read = 0;
    struct iovec local, remote;

    if (use_peekdata)
        return readstr_peekdata(addr, max_size);

    remain = addr - (addr & page_mask);
    buf = (char *) malloc(max_size + 1);

    while (read < max_size) {
        local.iov_base = (void *) (buf + read);
        local.iov_len = remain;
        remote.iov_base = (void *) (addr + read);
        remote.iov_len = remain;

        errno = 0;
        if (process_vm_readv(tid, &local, 1, &remote, 1, 0) > 0) {
            if (memchr(buf + read, '\0', remain))
                return buf;
            read += remain;
        } else if (errno == ENOSYS || errno == EPERM) {
            perror("process_vm_readv");
            use_peekdata = true;
            free(buf);
            return readstr_peekdata(addr, max_size);
        } else {
            if (errno && errno != EFAULT && errno != EIO)
                perror("process_vm_readv");
            buf[read] = 0;
            return buf;
        }

        remain = page_size < max_size - read ? page_size : max_size - read;
    }
    buf[max_size] = 0;
    return buf;
#endif
}

char *pt_debugger::readstr_peekdata(unsigned long addr, size_t max_size) {
    size_t size = 4096, read = 0;
    char *buf = (char *) malloc(size);
    union {
        ptrace_read_t val;
        char byte[sizeof(ptrace_read_t)];
    } data;

    while (true) {
        if (read + sizeof(ptrace_read_t) > size) {
            if (max_size && size >= max_size) {
                buf[max_size-1] = 0;
                break;
            }

            size += 4096;
            if (max_size && size > max_size)
                size = max_size;

            void *nbuf = realloc(buf, size);
            if (!nbuf) {
                buf[size-4097] = 0;
                break;
            }
            buf = (char *) nbuf;
        }
#if PTBOX_FREEBSD
        // TODO: we could use PT_IO to speed up this entire function by reading chunks rather than byte
        data.val = ptrace(PT_READ_D, tid, (caddr_t) (addr + read), 0);
#else
        errno = 0;
        data.val = ptrace(PTRACE_PEEKDATA, tid, addr + read, NULL);
        if (data.val == -1 && errno)
            perror("ptrace(PTRACE_PEEKDATA)");
#endif
        memcpy(buf + read, data.byte, sizeof(ptrace_read_t));
        if (has_null(data.byte, sizeof(ptrace_read_t)))
            break;
        read += sizeof(ptrace_read_t);
    }
    return buf;
}

void pt_debugger::freestr(char *buf) {
    free(buf);
}

pt_debugger::~pt_debugger() {}
<|endoftext|>


<commit_before>//CODEIMGAME
#include "../graphics.hpp"
#include "sstream"
#include "vector"
#include "stdlib.h"
#include "time.h"
#include "math.h"

using namespace genv;
using namespace std;

const int kx = 1330;
const int ky = 600;

struct Sboxok
{
	int x;
	int y;
	int vx;
	int vy;
	unsigned char rr,gg,bb;
	int elet;

	Sboxok (int ex, int ey, int szin)
	{
		x = ex;
		y = ey;
		vx=rand() % 10 -5;
		vy=-(rand() % 10 +5);
		elet = 100;

		if (szin<255) 					{rr=255-(szin-0*255); 	gg=(szin-0*255); 		bb=000;} 				else
		if (szin>255 and szin<2*255) 	{rr=000; 				gg=255-(szin-1*255); 	bb=(szin-1*255);} 		else
		if (szin>2*255) 				{rr=(szin-2*255); 		gg=000; 				bb=255-(szin-2*255);}
	}

	void supdate();
	void srajzol();

};

void Sboxok::supdate()
{
	x+=vx;
	y+=vy;
	if (x>=kx or x<0) {vx=-vx; x+=vx;}
	if (y>=ky or y<0) {vy=-floor(vy/2); y+=vy;}
	vy++;
	elet--;
}

void Sboxok::srajzol()
{
	if (x>=kx or x<0) return;
	if (y>=ky or y<0) return;
	gout << color(rr,gg,bb)
		<< move_to(x,y)
		<< box(10,10);
}

std::vector<Sboxok> v;
int szin = 0;

void updatedraw()
{

	for (vector<Sboxok>::iterator i=v.begin(); i!=v.end();)
	{
		i->supdate();
		i->srajzol();
		if(i->elet<=0) i = v.erase(i);
		else ++i;
	}
}

int main()
{
	srand (time(NULL));
	gout.open(kx,ky,true);

	gout.showmouse(false);

	gin.timer(20);

	event ev;
	while(gin >> ev and ev.keycode!=key_escape) {
		if (ev.type==ev_timer) {

			gout << color(000,000,000)
				<< move_to(0,0)
				<< box_to(1329,599);

			updatedraw();

			gout << refresh;
		}

		if (ev.type==ev_mouse)
		{
			Sboxok b(ev.pos_x,ev.pos_y,szin);
			szin++; if (szin>3*255) szin=0;
			v.push_back(b);
		}
	}
	return 0;
}
<commit_msg>Asztali<commit_after>//CODEINGAME
#include "../graphics.hpp"
#include "sstream"
#include "vector"
#include "stdlib.h"
#include "time.h"
#include "math.h"

using namespace genv;
using namespace std;

const int kx = 1330;
const int ky = 600;

struct Sboxok
{
	int x;
	int y;
	int vx;
	int vy;
	unsigned char rr,gg,bb;
	int elet;

	Sboxok (int ex, int ey, int szin)
	{
		x = ex;
		y = ey;
		vx=rand() % 10 -5;
		vy=-(rand() % 10 +5);
		elet = 100;

		if (szin<255) 					{rr=255-(szin-0*255); 	gg=(szin-0*255); 		bb=000;} 				else
		if (szin>255 and szin<2*255) 	{rr=000; 				gg=255-(szin-1*255); 	bb=(szin-1*255);} 		else
		if (szin>2*255) 				{rr=(szin-2*255); 		gg=000; 				bb=255-(szin-2*255);}
	}

	void supdate();
	void srajzol();

};

void Sboxok::supdate()
{
	x+=vx;
	y+=vy;
	if (x>=kx or x<0) {vx=-vx; x+=vx;}
	if (y>=ky or y<0) {vy=-floor(vy/2); y+=vy;}
	vy++;
	elet--;
}

void Sboxok::srajzol()
{
	if (x>=kx or x<0) return;
	if (y>=ky or y<0) return;
	gout << color(rr,gg,bb)
		<< move_to(x,y)
		<< box(10,10);
}

std::vector<Sboxok> v;
int szin = 0;

void updatedraw()
{

	for (vector<Sboxok>::iterator i=v.begin(); i!=v.end();)
	{
		i->supdate();
		i->srajzol();
		if(i->elet<=0) i = v.erase(i);
		else ++i;
	}
}

int main()
{
	srand (time(NULL));
	gout.open(kx,ky,true);

	gout.showmouse(false);

	gin.timer(20);

	event ev;
	while(gin >> ev and ev.keycode!=key_escape) {
		if (ev.type==ev_timer) {

			gout << color(000,000,000)
				<< move_to(0,0)
				<< box_to(1329,599);

			updatedraw();

			gout << refresh;
		}

		if (ev.type==ev_mouse)
		{
			Sboxok b(ev.pos_x,ev.pos_y,szin);
			szin++; if (szin>3*255) szin=0;
			v.push_back(b);
		}
	}
	return 0;
}
<|endoftext|>


<commit_before>#include <cstdlib>

#include "map.h"

using worker::Entity;
using worker::List;
using shoveler::TilemapTilesTile;

static const int halfMapWidth = 100;
static const int halfMapHeight = 100;

static ChunkData createChunk(int x, int y, int chunkSize);

List<ChunkData> generateMapChunks(int chunkSize)
{
	List<ChunkData> chunks;

	for(int x = -halfMapWidth; x < halfMapWidth; x += chunkSize) {
		for(int z = -halfMapHeight; z < halfMapHeight; z += chunkSize) {
			chunks.emplace_back(createChunk(x, z, chunkSize));
		}
	}

	return chunks;
}

static ChunkData createChunk(int x, int z, int chunkSize)
{
	ChunkData chunk;
	chunk.position = {x + chunkSize / 2.0, 0.0, z + chunkSize / 2.0};

	int rockSeedModulo = 5 + (rand() % 100);
	int bushSeedModulo = 5 + (rand() % 25);
	int treeSeedModulo = 5 + (rand() % 50);

	for(int i = 0; i < chunkSize; i++) {
		for(int j = 0; j < chunkSize; j++) {
			TilemapTilesTile backgroundTile;
			TilemapTilesTile foregroundTile;

			foregroundTile.set_tileset_column(0);
			foregroundTile.set_tileset_row(0);
			foregroundTile.set_tileset_id(0);
			foregroundTile.set_colliding(false);

			// fill background with grass
			int grassColumn = rand() % 3;
			int grassRow = rand() % 2;
			backgroundTile.set_tileset_column(grassColumn);
			backgroundTile.set_tileset_row(grassRow);
			backgroundTile.set_tileset_id(2);
			foregroundTile.set_colliding(false);

			// place rocks
			int rockSeed = rand() % rockSeedModulo;
			if(rockSeed == 0) {
				backgroundTile.set_tileset_column(5);
				backgroundTile.set_tileset_row(0);
				backgroundTile.set_colliding(true);
			}

			// place bushes
			int bushSeed = rand() % bushSeedModulo;
			if(bushSeed == 0) {
				backgroundTile.set_tileset_column(5);
				backgroundTile.set_tileset_row(1);
				backgroundTile.set_colliding(true);
			}

			// place trees
			do {
				if(i > 0) {
					const TilemapTilesTile& previousRow = chunk.backgroundTiles[(i - 1) * chunkSize + j];

					// complete left part of tree
					if(previousRow.tileset_column() == 3 && previousRow.tileset_row() == 0) {
						foregroundTile.set_tileset_column(3);
						foregroundTile.set_tileset_row(1);
						foregroundTile.set_tileset_id(2);
						break;
					}

					// complete right part of tree
					if(previousRow.tileset_column() == 4 && previousRow.tileset_row() == 0) {
						foregroundTile.set_tileset_column(4);
						foregroundTile.set_tileset_row(1);
						foregroundTile.set_tileset_id(2);
						break;
					}
				}

				if(j > 0) {
					const TilemapTilesTile &previousTile = *chunk.backgroundTiles.rbegin();

					// complete bottom part of tree
					if (previousTile.tileset_column() == 3 && previousTile.tileset_row() == 0) {
						backgroundTile.set_tileset_column(4);
						backgroundTile.set_tileset_row(0);
						backgroundTile.set_colliding(true);
						break;
					}
				}

				if(i > 0 && j < chunkSize - 1) {
					const TilemapTilesTile& previousRowNext = chunk.backgroundTiles[(i - 1) * chunkSize + j + 1];
					// reject positions that already have a tree starting on the bottom right neighbor tile
					if (previousRowNext.tileset_column() == 3 && previousRowNext.tileset_row() == 0) {
						break;
					}
				}

				// reject positions that don't fit into the chunk
				if(i == chunkSize - 1 || j == chunkSize - 1) {
					break;
				}

				// start new tree
				int treeSeed = rand() % treeSeedModulo;
				if(treeSeed == 0) {
					backgroundTile.set_tileset_column(3);
					backgroundTile.set_tileset_row(0);
					backgroundTile.set_colliding(true);
				}
			} while (false);

			chunk.backgroundTiles.emplace_back(backgroundTile);
			chunk.foregroundTiles.emplace_back(foregroundTile);
		}
	}

	return chunk;
}
<commit_msg>added startig area for tiles map<commit_after>#include <cstdlib>

#include "map.h"

using worker::Entity;
using worker::List;
using shoveler::TilemapTilesTile;

static const int halfMapWidth = 100;
static const int halfMapHeight = 100;

static ChunkData createStartingAreaBottomLeft(int chunkSize);
static ChunkData createStartingAreaBottomRight(int chunkSize);
static ChunkData createStartingAreaTopLeft(int chunkSize);
static ChunkData createStartingAreaTopRight(int chunkSize);
static ChunkData createChunk(int x, int y, int chunkSize);

List<ChunkData> generateMapChunks(int chunkSize)
{
	List<ChunkData> chunks;

	for(int x = -halfMapWidth; x < halfMapWidth; x += chunkSize) {
		for(int z = -halfMapHeight; z < halfMapHeight; z += chunkSize) {
			if(x == -chunkSize && z == -chunkSize) {
				chunks.emplace_back(createStartingAreaBottomLeft(chunkSize));
			} else if(x == 0 && z == -chunkSize) {
				chunks.emplace_back(createStartingAreaBottomRight(chunkSize));
			} else if(x == -chunkSize && z == 0) {
				chunks.emplace_back(createStartingAreaTopLeft(chunkSize));
			} else if(x == 0 && z == 0) {
				chunks.emplace_back(createStartingAreaTopRight(chunkSize));
			} else {
				chunks.emplace_back(createChunk(x, z, chunkSize));
			}
		}
	}

	return chunks;
}

static ChunkData createStartingAreaBottomLeft(int chunkSize)
{
	ChunkData chunk;
	chunk.position = {-chunkSize / 2.0, 0.0, -chunkSize / 2.0};

	for(int i = 0; i < chunkSize; i++) {
		for(int j = 0; j < chunkSize; j++) {
			TilemapTilesTile backgroundTile;
			TilemapTilesTile foregroundTile;

			foregroundTile.set_tileset_column(0);
			foregroundTile.set_tileset_row(0);
			foregroundTile.set_tileset_id(0);
			foregroundTile.set_colliding(false);

			// fill background with grass
			int grassColumn = rand() % 3;
			int grassRow = rand() % 2;
			backgroundTile.set_tileset_column(grassColumn);
			backgroundTile.set_tileset_row(grassRow);
			backgroundTile.set_tileset_id(2);
			foregroundTile.set_colliding(false);

			// place boundary rocks
			if((i == 0 || j == 0) && i != chunkSize - 1 && j != chunkSize - 1) {
				backgroundTile.set_tileset_column(5);
				backgroundTile.set_tileset_row(0);
				backgroundTile.set_colliding(true);
			}

			chunk.backgroundTiles.emplace_back(backgroundTile);
			chunk.foregroundTiles.emplace_back(foregroundTile);
		}
	}

	return chunk;
}

static ChunkData createStartingAreaBottomRight(int chunkSize)
{
	ChunkData chunk;
	chunk.position = {chunkSize / 2.0, 0.0, -chunkSize / 2.0};

	for(int i = 0; i < chunkSize; i++) {
		for(int j = 0; j < chunkSize; j++) {
			TilemapTilesTile backgroundTile;
			TilemapTilesTile foregroundTile;

			foregroundTile.set_tileset_column(0);
			foregroundTile.set_tileset_row(0);
			foregroundTile.set_tileset_id(0);
			foregroundTile.set_colliding(false);

			// fill background with grass
			int grassColumn = rand() % 3;
			int grassRow = rand() % 2;
			backgroundTile.set_tileset_column(grassColumn);
			backgroundTile.set_tileset_row(grassRow);
			backgroundTile.set_tileset_id(2);
			foregroundTile.set_colliding(false);

			// place boundary rocks
			if((i == 0 || j == chunkSize - 1) && i != chunkSize - 1 && j != 0) {
				backgroundTile.set_tileset_column(5);
				backgroundTile.set_tileset_row(0);
				backgroundTile.set_colliding(true);
			}

			chunk.backgroundTiles.emplace_back(backgroundTile);
			chunk.foregroundTiles.emplace_back(foregroundTile);
		}
	}

	return chunk;
}

static ChunkData createStartingAreaTopLeft(int chunkSize)
{
	ChunkData chunk;
	chunk.position = {-chunkSize / 2.0, 0.0, chunkSize / 2.0};

	for(int i = 0; i < chunkSize; i++) {
		for(int j = 0; j < chunkSize; j++) {
			TilemapTilesTile backgroundTile;
			TilemapTilesTile foregroundTile;

			foregroundTile.set_tileset_column(0);
			foregroundTile.set_tileset_row(0);
			foregroundTile.set_tileset_id(0);
			foregroundTile.set_colliding(false);

			// fill background with grass
			int grassColumn = rand() % 3;
			int grassRow = rand() % 2;
			backgroundTile.set_tileset_column(grassColumn);
			backgroundTile.set_tileset_row(grassRow);
			backgroundTile.set_tileset_id(2);
			foregroundTile.set_colliding(false);

			// place boundary rocks
			if((i == chunkSize - 1 || j == 0) && i != 0 && j != chunkSize - 1) {
				backgroundTile.set_tileset_column(5);
				backgroundTile.set_tileset_row(0);
				backgroundTile.set_colliding(true);
			}

			chunk.backgroundTiles.emplace_back(backgroundTile);
			chunk.foregroundTiles.emplace_back(foregroundTile);
		}
	}

	return chunk;
}

static ChunkData createStartingAreaTopRight(int chunkSize)
{
	ChunkData chunk;
	chunk.position = {chunkSize / 2.0, 0.0, chunkSize / 2.0};

	for(int i = 0; i < chunkSize; i++) {
		for(int j = 0; j < chunkSize; j++) {
			TilemapTilesTile backgroundTile;
			TilemapTilesTile foregroundTile;

			foregroundTile.set_tileset_column(0);
			foregroundTile.set_tileset_row(0);
			foregroundTile.set_tileset_id(0);
			foregroundTile.set_colliding(false);

			// fill background with grass
			int grassColumn = rand() % 3;
			int grassRow = rand() % 2;
			backgroundTile.set_tileset_column(grassColumn);
			backgroundTile.set_tileset_row(grassRow);
			backgroundTile.set_tileset_id(2);
			foregroundTile.set_colliding(false);

			// place boundary rocks
			if((i == chunkSize - 1 || j == chunkSize - 1) && i != 0 && j != 0) {
				backgroundTile.set_tileset_column(5);
				backgroundTile.set_tileset_row(0);
				backgroundTile.set_colliding(true);
			}

			chunk.backgroundTiles.emplace_back(backgroundTile);
			chunk.foregroundTiles.emplace_back(foregroundTile);
		}
	}

	return chunk;
}

static ChunkData createChunk(int x, int z, int chunkSize)
{
	ChunkData chunk;
	chunk.position = {x + chunkSize / 2.0, 0.0, z + chunkSize / 2.0};

	int rockSeedModulo = 5 + (rand() % 100);
	int bushSeedModulo = 5 + (rand() % 25);
	int treeSeedModulo = 5 + (rand() % 50);

	for(int i = 0; i < chunkSize; i++) {
		for(int j = 0; j < chunkSize; j++) {
			TilemapTilesTile backgroundTile;
			TilemapTilesTile foregroundTile;

			foregroundTile.set_tileset_column(0);
			foregroundTile.set_tileset_row(0);
			foregroundTile.set_tileset_id(0);
			foregroundTile.set_colliding(false);

			// fill background with grass
			int grassColumn = rand() % 3;
			int grassRow = rand() % 2;
			backgroundTile.set_tileset_column(grassColumn);
			backgroundTile.set_tileset_row(grassRow);
			backgroundTile.set_tileset_id(2);
			foregroundTile.set_colliding(false);

			// place rocks
			int rockSeed = rand() % rockSeedModulo;
			if(rockSeed == 0) {
				backgroundTile.set_tileset_column(5);
				backgroundTile.set_tileset_row(0);
				backgroundTile.set_colliding(true);
			}

			// place bushes
			int bushSeed = rand() % bushSeedModulo;
			if(bushSeed == 0) {
				backgroundTile.set_tileset_column(5);
				backgroundTile.set_tileset_row(1);
				backgroundTile.set_colliding(true);
			}

			// place trees
			do {
				if(i > 0) {
					const TilemapTilesTile& previousRow = chunk.backgroundTiles[(i - 1) * chunkSize + j];

					// complete left part of tree
					if(previousRow.tileset_column() == 3 && previousRow.tileset_row() == 0) {
						foregroundTile.set_tileset_column(3);
						foregroundTile.set_tileset_row(1);
						foregroundTile.set_tileset_id(2);
						break;
					}

					// complete right part of tree
					if(previousRow.tileset_column() == 4 && previousRow.tileset_row() == 0) {
						foregroundTile.set_tileset_column(4);
						foregroundTile.set_tileset_row(1);
						foregroundTile.set_tileset_id(2);
						break;
					}
				}

				if(j > 0) {
					const TilemapTilesTile &previousTile = *chunk.backgroundTiles.rbegin();

					// complete bottom part of tree
					if (previousTile.tileset_column() == 3 && previousTile.tileset_row() == 0) {
						backgroundTile.set_tileset_column(4);
						backgroundTile.set_tileset_row(0);
						backgroundTile.set_colliding(true);
						break;
					}
				}

				if(i > 0 && j < chunkSize - 1) {
					const TilemapTilesTile& previousRowNext = chunk.backgroundTiles[(i - 1) * chunkSize + j + 1];
					// reject positions that already have a tree starting on the bottom right neighbor tile
					if (previousRowNext.tileset_column() == 3 && previousRowNext.tileset_row() == 0) {
						break;
					}
				}

				// reject positions that don't fit into the chunk
				if(i == chunkSize - 1 || j == chunkSize - 1) {
					break;
				}

				// start new tree
				int treeSeed = rand() % treeSeedModulo;
				if(treeSeed == 0) {
					backgroundTile.set_tileset_column(3);
					backgroundTile.set_tileset_row(0);
					backgroundTile.set_colliding(true);
				}
			} while (false);

			chunk.backgroundTiles.emplace_back(backgroundTile);
			chunk.foregroundTiles.emplace_back(foregroundTile);
		}
	}

	return chunk;
}
<|endoftext|>


<commit_before>#include <reactive/bridge.hpp>
#include <reactive/consume.hpp>
#include <boost/optional.hpp>
#include <boost/test/unit_test.hpp>
#include <lua.hpp>

namespace Si
{
	struct lua_deleter
	{
		void operator()(lua_State *L) const
		{
			lua_close(L);
		}
	};

	std::unique_ptr<lua_State, lua_deleter> open_lua()
	{
		auto L = std::unique_ptr<lua_State, lua_deleter>(luaL_newstate());
		if (!L)
		{
			throw std::bad_alloc();
		}
		return L;
	}

	typedef rx::observer<int> yield_destination;

	static int yield(lua_State *L)
	{
		yield_destination &dest = *static_cast<yield_destination *>(lua_touserdata(L, lua_upvalueindex(1)));
		int element = lua_tointeger(L, 1);
		dest.got_element(element);
		return lua_yield(L, 0);
	}

	BOOST_AUTO_TEST_CASE(lua)
	{
		auto L = open_lua();
		// src
		BOOST_REQUIRE_EQUAL(0, luaL_loadstring(L.get(), "return function (yield) yield(4) end"));
		// fn
		if (0 != lua_pcall(L.get(), 0, 1, 0))
		{
			throw std::runtime_error(lua_tostring(L.get(), -1));
		}

		lua_State * const coro = lua_newthread(L.get());
		lua_xmove(L.get(), coro, 1);

		rx::bridge<int> yielded;
		// fn &yielded
		lua_pushlightuserdata(coro, &static_cast<yield_destination &>(yielded));
		// fn yield[&yielded]
		lua_pushcclosure(coro, yield, 1);

		boost::optional<int> got;
		auto consumer = rx::consume<int>([&got](boost::optional<int> element)
		{
			BOOST_REQUIRE(element);
			got = element;
		});

		yielded.async_get_one(consumer);
		if (LUA_YIELD != lua_resume(L.get(), 1))
		{
			throw std::runtime_error(lua_tostring(coro, -1));
		}
		BOOST_CHECK_EQUAL(boost::make_optional(4), got);
	}
}
<commit_msg>fix the lua thread test<commit_after>#include <reactive/bridge.hpp>
#include <reactive/consume.hpp>
#include <boost/optional.hpp>
#include <boost/test/unit_test.hpp>
#include <lua.hpp>

namespace Si
{
	struct lua_deleter
	{
		void operator()(lua_State *L) const
		{
			lua_close(L);
		}
	};

	std::unique_ptr<lua_State, lua_deleter> open_lua()
	{
		auto L = std::unique_ptr<lua_State, lua_deleter>(luaL_newstate());
		if (!L)
		{
			throw std::bad_alloc();
		}
		return L;
	}

	typedef rx::observer<int> yield_destination;

	static int yield(lua_State *L)
	{
		yield_destination &dest = *static_cast<yield_destination *>(lua_touserdata(L, lua_upvalueindex(1)));
		int element = lua_tointeger(L, 1);
		dest.got_element(element);
		return lua_yield(L, 0);
	}

	BOOST_AUTO_TEST_CASE(lua)
	{
		auto L = open_lua();

		lua_State * const coro = lua_newthread(L.get());
		BOOST_REQUIRE_EQUAL(0, luaL_loadstring(coro, "return function (yield) yield(4) yield(5) end"));
		if (0 != lua_pcall(coro, 0, 1, 0))
		{
			throw std::runtime_error(lua_tostring(L.get(), -1));
		}

		rx::bridge<int> yielded;
		// fn &yielded
		lua_pushlightuserdata(coro, &static_cast<yield_destination &>(yielded));
		// fn yield[&yielded]
		lua_pushcclosure(coro, yield, 1);

		boost::optional<int> got;
		auto consumer = rx::consume<int>([&got](boost::optional<int> element)
		{
			BOOST_REQUIRE(element);
			got = element;
		});

		{
			yielded.async_get_one(consumer);
			int rc = lua_resume(coro, 1);
			if (LUA_YIELD != rc)
			{
				throw std::runtime_error(lua_tostring(coro, -1));
			}
			BOOST_CHECK_EQUAL(boost::make_optional(4), got);
		}

		{
			yielded.async_get_one(consumer);
			int rc = lua_resume(coro, 1);
			if (LUA_YIELD != rc)
			{
				throw std::runtime_error(lua_tostring(coro, -1));
			}
			BOOST_CHECK_EQUAL(boost::make_optional(5), got);
		}
	}
}
<|endoftext|>


<commit_before>#include "InputMesh.h"

#include <maya/MFnMesh.h>
#include <maya/MDataBlock.h>
#include <maya/MFloatArray.h>
#include <maya/MFloatPointArray.h>
#include <maya/MFloatVectorArray.h>
#include <maya/MIntArray.h>
#include <maya/MMatrix.h>

#include "util.h"

InputMesh::InputMesh(int assetId, int inputIdx) :
    Input(assetId, inputIdx),
    myInputObjectId(-1),
    myInputGeoId(-1)
{
    CHECK_HAPI(HAPI_CreateInputAsset(&myInputAssetId, NULL));
    Util::statusCheckLoop();

    myInputObjectId = 0;
    myInputGeoId = 0;

    CHECK_HAPI(HAPI_ConnectAssetGeometry(
                myInputAssetId, myInputObjectId,
                myAssetId, myInputIdx
                ));
}

InputMesh::~InputMesh()
{
    CHECK_HAPI(HAPI_DestroyAsset(myInputAssetId));
}

Input::AssetInputType
InputMesh::assetInputType() const
{
    return Input::AssetInputType_Mesh;
}

void
InputMesh::setInputTransform(MDataHandle &dataHandle)
{
    MMatrix transformMatrix = dataHandle.asMatrix();

    float matrix[16];
    transformMatrix.get(reinterpret_cast<float(*)[4]>(matrix));

    HAPI_TransformEuler transformEuler;
    HAPI_ConvertMatrixToEuler(matrix, HAPI_SRT, HAPI_XYZ, &transformEuler);
    HAPI_SetObjectTransform(
            myInputAssetId, myInputObjectId,
            &transformEuler
            );
}

void
InputMesh::setInputGeo(
        MDataBlock &dataBlock,
        const MPlug &plug
        )
{
    MDataHandle dataHandle = dataBlock.inputValue(plug);

    // extract mesh data from Maya
    MObject meshObj = dataHandle.asMesh();

    MFnMesh meshFn(meshObj);

    // get face data
    MIntArray faceCounts;
    MIntArray vertexList;
    meshFn.getVertices(faceCounts, vertexList);
    Util::reverseWindingOrder(vertexList, faceCounts);

    // set up part info
    HAPI_PartInfo partInfo;
    HAPI_PartInfo_Init(&partInfo);
    partInfo.id = 0;
    partInfo.faceCount        = faceCounts.length();
    partInfo.vertexCount      = vertexList.length();
    partInfo.pointCount       = meshFn.numVertices();

    // copy data to arrays
    int * vl = new int[partInfo.vertexCount];
    int * fc = new int[partInfo.faceCount];
    vertexList.get(vl);
    faceCounts.get(fc);

    // Set the data
    HAPI_SetPartInfo(
            myInputAssetId, myInputObjectId, myInputGeoId,
            &partInfo
            );
    HAPI_SetFaceCounts(
            myInputAssetId, myInputObjectId, myInputGeoId,
            fc, 0, partInfo.faceCount
            );
    HAPI_SetVertexList(
            myInputAssetId, myInputObjectId, myInputGeoId,
            vl, 0, partInfo.vertexCount
            );

    // Set position attributes.
    HAPI_AttributeInfo pos_attr_info;
    pos_attr_info.exists             = true;
    pos_attr_info.owner              = HAPI_ATTROWNER_POINT;
    pos_attr_info.storage            = HAPI_STORAGETYPE_FLOAT;
    pos_attr_info.count              = meshFn.numVertices();
    pos_attr_info.tupleSize          = 3;
    HAPI_AddAttribute(
            myInputAssetId, myInputObjectId, myInputGeoId,
            "P", &pos_attr_info
            );

    HAPI_SetAttributeFloatData(
            myInputAssetId, myInputObjectId, myInputGeoId,
            "P", &pos_attr_info,
            meshFn.getRawPoints(NULL), 0, meshFn.numVertices()
            );

    // normals
    {
        // get normal IDs
        MIntArray normalCounts;
        MIntArray normalIds;
        meshFn.getNormalIds(normalCounts, normalIds);

        if(normalIds.length())
        {
            // reverse winding order
            Util::reverseWindingOrder(normalIds, faceCounts);

            // get normal values
            const float* rawNormals = meshFn.getRawNormals(NULL);

            // build the per-vertex normals
            std::vector<float> vertexNormals;
            vertexNormals.reserve(normalIds.length() * 3);
            for(unsigned int i = 0; i < normalIds.length(); ++i)
            {
                vertexNormals.push_back(rawNormals[normalIds[i] * 3 + 0]);
                vertexNormals.push_back(rawNormals[normalIds[i] * 3 + 1]);
                vertexNormals.push_back(rawNormals[normalIds[i] * 3 + 2]);
            }

            // add and set it to HAPI
            HAPI_AttributeInfo attributeInfo;
            attributeInfo.exists = true;
            attributeInfo.owner = HAPI_ATTROWNER_VERTEX;
            attributeInfo.storage = HAPI_STORAGETYPE_FLOAT;
            attributeInfo.count = normalIds.length();
            attributeInfo.tupleSize = 3;
            HAPI_AddAttribute(
                    myInputAssetId, myInputObjectId, myInputGeoId,
                    "N", &attributeInfo
                    );

            HAPI_SetAttributeFloatData(myInputAssetId, myInputObjectId, myInputGeoId,
                    "N", &attributeInfo,
                    &vertexNormals.front(), 0, normalIds.length()
                    );
        }
    }

    // UVs
    {
        // get UV IDs
        MIntArray uvCounts;
        MIntArray uvIds;
        meshFn.getAssignedUVs(uvCounts, uvIds);

        // if there's UVs
        if(uvIds.length())
        {
            // reverse winding order
            Util::reverseWindingOrder(uvIds, uvCounts);

            // get UV values
            MFloatArray uArray;
            MFloatArray vArray;
            meshFn.getUVs(uArray, vArray);

            // build the per-vertex UVs
            std::vector<float> vertexUVs;
            vertexUVs.reserve(vertexList.length() * 3);
            unsigned int uvIdIndex = 0;
            for(unsigned int i = 0; i < uvCounts.length(); ++i)
            {
                if(uvCounts[i] == faceCounts[i])
                {
                    // has UVs assigned
                    for(int j = 0; j < uvCounts[i]; ++j)
                    {
                        vertexUVs.push_back(uArray[uvIds[uvIdIndex]]);
                        vertexUVs.push_back(vArray[uvIds[uvIdIndex]]);
                        vertexUVs.push_back(0);

                        uvIdIndex++;
                    }
                }
                else
                {
                    // no UVs assigned
                    for(int j = 0; j < faceCounts[i]; ++j)
                    {
                        vertexUVs.push_back(0);
                        vertexUVs.push_back(0);
                        vertexUVs.push_back(0);
                    }
                }
            }

            // add and set it to HAPI
            HAPI_AttributeInfo attributeInfo;
            attributeInfo.exists = true;
            attributeInfo.owner = HAPI_ATTROWNER_VERTEX;
            attributeInfo.storage = HAPI_STORAGETYPE_FLOAT;
            attributeInfo.count = vertexList.length();
            attributeInfo.tupleSize = 3;
            HAPI_AddAttribute(
                    myInputAssetId, myInputObjectId, myInputGeoId,
                    "uv", &attributeInfo
                    );

            HAPI_SetAttributeFloatData(
                    myInputAssetId, myInputObjectId, myInputGeoId,
                    "uv", &attributeInfo,
                    &vertexUVs.front(), 0, vertexList.length()
                    );
        }
    }

    // Commit it
    HAPI_CommitGeo(myInputAssetId, myInputObjectId, myInputGeoId);

    delete[] vl;
    delete[] fc;
}
<commit_msg>Add color sets support for input mesh<commit_after>#include "InputMesh.h"

#include <maya/MFnMesh.h>
#include <maya/MDataBlock.h>
#include <maya/MFloatArray.h>
#include <maya/MFloatPointArray.h>
#include <maya/MFloatVectorArray.h>
#include <maya/MIntArray.h>
#include <maya/MMatrix.h>

#include "util.h"

InputMesh::InputMesh(int assetId, int inputIdx) :
    Input(assetId, inputIdx),
    myInputObjectId(-1),
    myInputGeoId(-1)
{
    CHECK_HAPI(HAPI_CreateInputAsset(&myInputAssetId, NULL));
    Util::statusCheckLoop();

    myInputObjectId = 0;
    myInputGeoId = 0;

    CHECK_HAPI(HAPI_ConnectAssetGeometry(
                myInputAssetId, myInputObjectId,
                myAssetId, myInputIdx
                ));
}

InputMesh::~InputMesh()
{
    CHECK_HAPI(HAPI_DestroyAsset(myInputAssetId));
}

Input::AssetInputType
InputMesh::assetInputType() const
{
    return Input::AssetInputType_Mesh;
}

void
InputMesh::setInputTransform(MDataHandle &dataHandle)
{
    MMatrix transformMatrix = dataHandle.asMatrix();

    float matrix[16];
    transformMatrix.get(reinterpret_cast<float(*)[4]>(matrix));

    HAPI_TransformEuler transformEuler;
    HAPI_ConvertMatrixToEuler(matrix, HAPI_SRT, HAPI_XYZ, &transformEuler);
    HAPI_SetObjectTransform(
            myInputAssetId, myInputObjectId,
            &transformEuler
            );
}

void
InputMesh::setInputGeo(
        MDataBlock &dataBlock,
        const MPlug &plug
        )
{
    MDataHandle dataHandle = dataBlock.inputValue(plug);

    // extract mesh data from Maya
    MObject meshObj = dataHandle.asMesh();

    MFnMesh meshFn(meshObj);

    // get face data
    MIntArray faceCounts;
    MIntArray vertexList;
    meshFn.getVertices(faceCounts, vertexList);
    Util::reverseWindingOrder(vertexList, faceCounts);

    // set up part info
    HAPI_PartInfo partInfo;
    HAPI_PartInfo_Init(&partInfo);
    partInfo.id = 0;
    partInfo.faceCount        = faceCounts.length();
    partInfo.vertexCount      = vertexList.length();
    partInfo.pointCount       = meshFn.numVertices();

    // copy data to arrays
    int * vl = new int[partInfo.vertexCount];
    int * fc = new int[partInfo.faceCount];
    vertexList.get(vl);
    faceCounts.get(fc);

    // Set the data
    HAPI_SetPartInfo(
            myInputAssetId, myInputObjectId, myInputGeoId,
            &partInfo
            );
    HAPI_SetFaceCounts(
            myInputAssetId, myInputObjectId, myInputGeoId,
            fc, 0, partInfo.faceCount
            );
    HAPI_SetVertexList(
            myInputAssetId, myInputObjectId, myInputGeoId,
            vl, 0, partInfo.vertexCount
            );

    // Set position attributes.
    HAPI_AttributeInfo pos_attr_info;
    pos_attr_info.exists             = true;
    pos_attr_info.owner              = HAPI_ATTROWNER_POINT;
    pos_attr_info.storage            = HAPI_STORAGETYPE_FLOAT;
    pos_attr_info.count              = meshFn.numVertices();
    pos_attr_info.tupleSize          = 3;
    HAPI_AddAttribute(
            myInputAssetId, myInputObjectId, myInputGeoId,
            "P", &pos_attr_info
            );

    HAPI_SetAttributeFloatData(
            myInputAssetId, myInputObjectId, myInputGeoId,
            "P", &pos_attr_info,
            meshFn.getRawPoints(NULL), 0, meshFn.numVertices()
            );

    // normals
    {
        // get normal IDs
        MIntArray normalCounts;
        MIntArray normalIds;
        meshFn.getNormalIds(normalCounts, normalIds);

        if(normalIds.length())
        {
            // reverse winding order
            Util::reverseWindingOrder(normalIds, faceCounts);

            // get normal values
            const float* rawNormals = meshFn.getRawNormals(NULL);

            // build the per-vertex normals
            std::vector<float> vertexNormals;
            vertexNormals.reserve(normalIds.length() * 3);
            for(unsigned int i = 0; i < normalIds.length(); ++i)
            {
                vertexNormals.push_back(rawNormals[normalIds[i] * 3 + 0]);
                vertexNormals.push_back(rawNormals[normalIds[i] * 3 + 1]);
                vertexNormals.push_back(rawNormals[normalIds[i] * 3 + 2]);
            }

            // add and set it to HAPI
            HAPI_AttributeInfo attributeInfo;
            attributeInfo.exists = true;
            attributeInfo.owner = HAPI_ATTROWNER_VERTEX;
            attributeInfo.storage = HAPI_STORAGETYPE_FLOAT;
            attributeInfo.count = normalIds.length();
            attributeInfo.tupleSize = 3;
            HAPI_AddAttribute(
                    myInputAssetId, myInputObjectId, myInputGeoId,
                    "N", &attributeInfo
                    );

            HAPI_SetAttributeFloatData(myInputAssetId, myInputObjectId, myInputGeoId,
                    "N", &attributeInfo,
                    &vertexNormals.front(), 0, normalIds.length()
                    );
        }
    }

    // UVs
    {
        // get UV IDs
        MIntArray uvCounts;
        MIntArray uvIds;
        meshFn.getAssignedUVs(uvCounts, uvIds);

        // if there's UVs
        if(uvIds.length())
        {
            // reverse winding order
            Util::reverseWindingOrder(uvIds, uvCounts);

            // get UV values
            MFloatArray uArray;
            MFloatArray vArray;
            meshFn.getUVs(uArray, vArray);

            // build the per-vertex UVs
            std::vector<float> vertexUVs;
            vertexUVs.reserve(vertexList.length() * 3);
            unsigned int uvIdIndex = 0;
            for(unsigned int i = 0; i < uvCounts.length(); ++i)
            {
                if(uvCounts[i] == faceCounts[i])
                {
                    // has UVs assigned
                    for(int j = 0; j < uvCounts[i]; ++j)
                    {
                        vertexUVs.push_back(uArray[uvIds[uvIdIndex]]);
                        vertexUVs.push_back(vArray[uvIds[uvIdIndex]]);
                        vertexUVs.push_back(0);

                        uvIdIndex++;
                    }
                }
                else
                {
                    // no UVs assigned
                    for(int j = 0; j < faceCounts[i]; ++j)
                    {
                        vertexUVs.push_back(0);
                        vertexUVs.push_back(0);
                        vertexUVs.push_back(0);
                    }
                }
            }

            // add and set it to HAPI
            HAPI_AttributeInfo attributeInfo;
            attributeInfo.exists = true;
            attributeInfo.owner = HAPI_ATTROWNER_VERTEX;
            attributeInfo.storage = HAPI_STORAGETYPE_FLOAT;
            attributeInfo.count = vertexList.length();
            attributeInfo.tupleSize = 3;
            HAPI_AddAttribute(
                    myInputAssetId, myInputObjectId, myInputGeoId,
                    "uv", &attributeInfo
                    );

            HAPI_SetAttributeFloatData(
                    myInputAssetId, myInputObjectId, myInputGeoId,
                    "uv", &attributeInfo,
                    &vertexUVs.front(), 0, vertexList.length()
                    );
        }
    }

    // Colors and Alphas
    {
        MString currentColorSetName;
        currentColorSetName = meshFn.currentColorSetName();

        MStringArray colorSetNames;
        meshFn.getColorSetNames(colorSetNames);

        MColor defaultUnsetColor;
        MColorArray colors;
        std::vector<float> buffer;
        for(unsigned int i = 0; i < colorSetNames.length(); i++)
        {
            const MString colorSetName = colorSetNames[i];

            MString colorAttributeName;
            MString alphaAttributeName;
            if(colorSetName == currentColorSetName)
            {
                colorAttributeName = "Cd";
                alphaAttributeName = "Alpha";
            }
            else
            {
                colorAttributeName = colorSetName;
                alphaAttributeName = colorSetName + "Alpha";
            }

            bool hasColor = false;
            bool hasAlpha = false;
            {
                MFnMesh::MColorRepresentation colorSetRepresentation =
                    meshFn.getColorRepresentation(colorSetName);

                switch(colorSetRepresentation)
                {
                    case MFnMesh::kAlpha:
                        hasAlpha = true;
                        break;
                    case MFnMesh::kRGB:
                        hasColor = true;
                        break;
                    case MFnMesh::kRGBA:
                        hasColor = true;
                        hasAlpha = true;
                        break;
                }
            }

            CHECK_MSTATUS(meshFn.getFaceVertexColors(
                        colors,
                        &colorSetName,
                        &defaultUnsetColor
                        ));

            // reverse winding order
            Util::reverseWindingOrder(colors, faceCounts);

            if(hasColor)
            {
                buffer.resize(3 * vertexList.length());
                for(unsigned int j = 0; j < vertexList.length(); j++)
                {
                    buffer[j * 3 + 0] = colors[j].r;
                    buffer[j * 3 + 1] = colors[j].g;
                    buffer[j * 3 + 2] = colors[j].b;
                }

                // add and set Cd
                HAPI_AttributeInfo colorAttributeInfo;
                colorAttributeInfo.exists = true;
                colorAttributeInfo.owner = HAPI_ATTROWNER_VERTEX;
                colorAttributeInfo.storage = HAPI_STORAGETYPE_FLOAT;
                colorAttributeInfo.count = vertexList.length();
                colorAttributeInfo.tupleSize = 3;
                HAPI_AddAttribute(
                        myInputAssetId, myInputObjectId, myInputGeoId,
                        colorAttributeName.asChar(), &colorAttributeInfo
                        );

                HAPI_SetAttributeFloatData(
                        myInputAssetId, myInputObjectId, myInputGeoId,
                        colorAttributeName.asChar(), &colorAttributeInfo,
                        &buffer.front(), 0, vertexList.length()
                        );
            }

            if(hasAlpha)
            {
                buffer.resize(vertexList.length());
                for(unsigned int j = 0; j < vertexList.length(); j++)
                {
                    buffer[j] = colors[j].a;
                }

                // add and set Alpha
                HAPI_AttributeInfo alphaAttributeInfo;
                alphaAttributeInfo.exists = true;
                alphaAttributeInfo.owner = HAPI_ATTROWNER_VERTEX;
                alphaAttributeInfo.storage = HAPI_STORAGETYPE_FLOAT;
                alphaAttributeInfo.count = vertexList.length();
                alphaAttributeInfo.tupleSize = 1;
                HAPI_AddAttribute(
                        myInputAssetId, myInputObjectId, myInputGeoId,
                        alphaAttributeName.asChar(), &alphaAttributeInfo
                        );

                HAPI_SetAttributeFloatData(
                        myInputAssetId, myInputObjectId, myInputGeoId,
                        alphaAttributeName.asChar(), &alphaAttributeInfo,
                        &buffer.front(), 0, vertexList.length()
                        );
            }
        }
    }

    // Commit it
    HAPI_CommitGeo(myInputAssetId, myInputObjectId, myInputGeoId);

    delete[] vl;
    delete[] fc;
}
<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2013-2019 Winlin

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.
*/
#include <srs_utest_app.hpp>

using namespace std;

#include <srs_kernel_error.hpp>
#include <srs_app_fragment.hpp>

// Disable coroutine test for OSX.
#if !defined(SRS_OSX)

#include <srs_app_st.hpp>

VOID TEST(AppCoroutineTest, Dummy)
{
    SrsDummyCoroutine dc;

    if (true) {
        EXPECT_EQ(0, dc.cid());

        srs_error_t err = dc.pull();
        EXPECT_TRUE(err != srs_success);
        EXPECT_TRUE(ERROR_THREAD_DUMMY == srs_error_code(err));
        srs_freep(err);

        err = dc.start();
        EXPECT_TRUE(err != srs_success);
        EXPECT_TRUE(ERROR_THREAD_DUMMY == srs_error_code(err));
        srs_freep(err);
    }

    if (true) {
        dc.stop();

        EXPECT_EQ(0, dc.cid());

        srs_error_t err = dc.pull();
        EXPECT_TRUE(err != srs_success);
        EXPECT_TRUE(ERROR_THREAD_DUMMY == srs_error_code(err));
        srs_freep(err);

        err = dc.start();
        EXPECT_TRUE(err != srs_success);
        EXPECT_TRUE(ERROR_THREAD_DUMMY == srs_error_code(err));
        srs_freep(err);
    }

    if (true) {
        dc.interrupt();

        EXPECT_EQ(0, dc.cid());

        srs_error_t err = dc.pull();
        EXPECT_TRUE(err != srs_success);
        EXPECT_TRUE(ERROR_THREAD_DUMMY == srs_error_code(err));
        srs_freep(err);

        err = dc.start();
        EXPECT_TRUE(err != srs_success);
        EXPECT_TRUE(ERROR_THREAD_DUMMY == srs_error_code(err));
        srs_freep(err);
    }
}

class MockCoroutineHandler : public ISrsCoroutineHandler {
public:
    SrsSTCoroutine* trd;
    srs_error_t err;
    srs_cond_t running;
    srs_cond_t exited;
    int cid;
    // Quit without error.
    bool quit;
public:
    MockCoroutineHandler() : trd(NULL), err(srs_success), cid(0), quit(false) {
        running = srs_cond_new();
        exited = srs_cond_new();
    }
    virtual ~MockCoroutineHandler() {
        srs_cond_destroy(running);
        srs_cond_destroy(exited);
    }
public:
    virtual srs_error_t cycle() {
        srs_error_t r0 = srs_success;

        srs_cond_signal(running);
        cid = _srs_context->get_id();

        while (!quit && (r0 = trd->pull()) == srs_success && err == srs_success) {
            srs_usleep(10 * SRS_UTIME_MILLISECONDS);
        }

        srs_cond_signal(exited);

        if (err != srs_success) {
            srs_freep(r0);
            return err;
        }

        return r0;
    }
};

VOID TEST(AppCoroutineTest, StartStop)
{
    if (true) {
        MockCoroutineHandler ch;
        SrsSTCoroutine sc("test", &ch);
        ch.trd = ≻
        EXPECT_EQ(0, sc.cid());

        // Thread stop after created.
        sc.stop();

        EXPECT_EQ(0, sc.cid());

        srs_error_t err = sc.pull();
        EXPECT_TRUE(srs_success != err);
        EXPECT_TRUE(ERROR_THREAD_TERMINATED == srs_error_code(err));
        srs_freep(err);

        // Should never reuse a disposed thread.
        err = sc.start();
        EXPECT_TRUE(srs_success != err);
        EXPECT_TRUE(ERROR_THREAD_DISPOSED == srs_error_code(err));
        srs_freep(err);
    }

    if (true) {
        MockCoroutineHandler ch;
        SrsSTCoroutine sc("test", &ch);
        ch.trd = ≻
        EXPECT_EQ(0, sc.cid());

        EXPECT_TRUE(srs_success == sc.start());
        EXPECT_TRUE(srs_success == sc.pull());

        srs_cond_timedwait(ch.running, 100 * SRS_UTIME_MILLISECONDS);
        EXPECT_TRUE(sc.cid() > 0);

        // Thread stop after started.
        sc.stop();

        srs_error_t err = sc.pull();
        EXPECT_TRUE(srs_success != err);
        EXPECT_TRUE(ERROR_THREAD_INTERRUPED == srs_error_code(err));
        srs_freep(err);

        // Should never reuse a disposed thread.
        err = sc.start();
        EXPECT_TRUE(srs_success != err);
        EXPECT_TRUE(ERROR_THREAD_DISPOSED == srs_error_code(err));
        srs_freep(err);
    }

    if (true) {
        MockCoroutineHandler ch;
        SrsSTCoroutine sc("test", &ch);
        ch.trd = ≻
        EXPECT_EQ(0, sc.cid());

        EXPECT_TRUE(srs_success == sc.start());
        EXPECT_TRUE(srs_success == sc.pull());

        // Error when start multiple times.
        srs_error_t err = sc.start();
        EXPECT_TRUE(srs_success != err);
        EXPECT_TRUE(ERROR_THREAD_STARTED == srs_error_code(err));
        srs_freep(err);

        err = sc.pull();
        EXPECT_TRUE(srs_success != err);
        EXPECT_TRUE(ERROR_THREAD_STARTED == srs_error_code(err));
        srs_freep(err);
    }
}

VOID TEST(AppCoroutineTest, Cycle)
{
    if (true) {
        MockCoroutineHandler ch;
        SrsSTCoroutine sc("test", &ch);
        ch.trd = ≻

        EXPECT_TRUE(srs_success == sc.start());
        EXPECT_TRUE(srs_success == sc.pull());

        // Set cycle to error.
        ch.err = srs_error_new(-1, "cycle");

        srs_cond_timedwait(ch.running, 100 * SRS_UTIME_MILLISECONDS);

        // The cycle error should be pulled.
        srs_error_t err = sc.pull();
        EXPECT_TRUE(srs_success != err);
        EXPECT_TRUE(-1 == srs_error_code(err));
        srs_freep(err);
    }

    if (true) {
        MockCoroutineHandler ch;
        SrsSTCoroutine sc("test", &ch, 250);
        ch.trd = ≻
        EXPECT_EQ(250, sc.cid());

        EXPECT_TRUE(srs_success == sc.start());
        EXPECT_TRUE(srs_success == sc.pull());

        // After running, the cid in cycle should equal to the thread.
        srs_cond_timedwait(ch.running, 100 * SRS_UTIME_MILLISECONDS);
        EXPECT_EQ(250, ch.cid);
    }

    if (true) {
        MockCoroutineHandler ch;
        SrsSTCoroutine sc("test", &ch);
        ch.trd = ≻

        EXPECT_TRUE(srs_success == sc.start());
        EXPECT_TRUE(srs_success == sc.pull());

        srs_cond_timedwait(ch.running, 100 * SRS_UTIME_MILLISECONDS);

        // Interrupt thread, set err to interrupted.
        sc.interrupt();

        // Set cycle to error.
        ch.err = srs_error_new(-1, "cycle");

        // When thread terminated, thread will get its error.
        srs_cond_timedwait(ch.exited, 100 * SRS_UTIME_MILLISECONDS);

        // Override the error by cycle error.
        sc.stop();

        // Should be cycle error.
        srs_error_t err = sc.pull();
        EXPECT_TRUE(srs_success != err);
        EXPECT_TRUE(-1 == srs_error_code(err));
        srs_freep(err);
    }

    if (true) {
        MockCoroutineHandler ch;
        SrsSTCoroutine sc("test", &ch);
        ch.trd = ≻

        EXPECT_TRUE(srs_success == sc.start());
        EXPECT_TRUE(srs_success == sc.pull());

        // Quit without error.
        ch.quit = true;

        // Wait for thread to done.
        srs_cond_timedwait(ch.exited, 100 * SRS_UTIME_MILLISECONDS);

        // Override the error by cycle error.
        sc.stop();

        // Should be cycle error.
        srs_error_t err = sc.pull();
        EXPECT_TRUE(srs_success == err);
        srs_freep(err);
    }
}

void* mock_st_thread_create(void *(*/*start*/)(void *arg), void */*arg*/, int /*joinable*/, int /*stack_size*/) {
    return NULL;
}

VOID TEST(AppCoroutineTest, StartThread)
{
    MockCoroutineHandler ch;
    SrsSTCoroutine sc("test", &ch);
    ch.trd = ≻

    _ST_THREAD_CREATE_PFN ov = _pfn_st_thread_create;
    _pfn_st_thread_create = (_ST_THREAD_CREATE_PFN)mock_st_thread_create;

    srs_error_t err = sc.start();
    _pfn_st_thread_create = ov;

    EXPECT_TRUE(srs_success != err);
    EXPECT_TRUE(ERROR_ST_CREATE_CYCLE_THREAD == srs_error_code(err));
    srs_freep(err);
}

#endif

VOID TEST(AppFragmentTest, CheckDuration)
{
	if (true) {
		SrsFragment frg;
		EXPECT_EQ(-1, frg.start_dts);
		EXPECT_EQ(0, frg.dur);
		EXPECT_FALSE(frg.sequence_header);
	}

	if (true) {
		SrsFragment frg;

		frg.append(0);
		EXPECT_EQ(0, frg.duration());

		frg.append(10);
		EXPECT_EQ(10 * SRS_UTIME_MILLISECONDS, frg.duration());

		frg.append(99);
		EXPECT_EQ(99 * SRS_UTIME_MILLISECONDS, frg.duration());

		frg.append(0x7fffffffLL);
		EXPECT_EQ(0x7fffffffLL * SRS_UTIME_MILLISECONDS, frg.duration());

		frg.append(0xffffffffLL);
		EXPECT_EQ(0xffffffffLL * SRS_UTIME_MILLISECONDS, frg.duration());

		frg.append(0x20c49ba5e353f7LL);
		EXPECT_EQ(0x20c49ba5e353f7LL * SRS_UTIME_MILLISECONDS, frg.duration());
	}

	if (true) {
		SrsFragment frg;

		frg.append(0);
		EXPECT_EQ(0, frg.duration());

		frg.append(0x7fffffffffffffffLL);
		EXPECT_EQ(0, frg.duration());
	}

	if (true) {
		SrsFragment frg;

		frg.append(100);
		EXPECT_EQ(0, frg.duration());

		frg.append(10);
		EXPECT_EQ(0, frg.duration());

		frg.append(100);
		EXPECT_EQ(90 * SRS_UTIME_MILLISECONDS, frg.duration());
	}

	if (true) {
		SrsFragment frg;

		frg.append(-10);
		EXPECT_EQ(0, frg.duration());

		frg.append(-5);
		EXPECT_EQ(0, frg.duration());

		frg.append(10);
		EXPECT_EQ(10 * SRS_UTIME_MILLISECONDS, frg.duration());
	}
}

<commit_msg>Add utest for tcp server<commit_after>/*
The MIT License (MIT)

Copyright (c) 2013-2019 Winlin

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.
*/
#include <srs_utest_app.hpp>

using namespace std;

#include <srs_kernel_error.hpp>
#include <srs_app_fragment.hpp>

// Disable coroutine test for OSX.
#if !defined(SRS_OSX)

#include <srs_app_st.hpp>

VOID TEST(AppCoroutineTest, Dummy)
{
    SrsDummyCoroutine dc;

    if (true) {
        EXPECT_EQ(0, dc.cid());

        srs_error_t err = dc.pull();
        EXPECT_TRUE(err != srs_success);
        EXPECT_TRUE(ERROR_THREAD_DUMMY == srs_error_code(err));
        srs_freep(err);

        err = dc.start();
        EXPECT_TRUE(err != srs_success);
        EXPECT_TRUE(ERROR_THREAD_DUMMY == srs_error_code(err));
        srs_freep(err);
    }

    if (true) {
        dc.stop();

        EXPECT_EQ(0, dc.cid());

        srs_error_t err = dc.pull();
        EXPECT_TRUE(err != srs_success);
        EXPECT_TRUE(ERROR_THREAD_DUMMY == srs_error_code(err));
        srs_freep(err);

        err = dc.start();
        EXPECT_TRUE(err != srs_success);
        EXPECT_TRUE(ERROR_THREAD_DUMMY == srs_error_code(err));
        srs_freep(err);
    }

    if (true) {
        dc.interrupt();

        EXPECT_EQ(0, dc.cid());

        srs_error_t err = dc.pull();
        EXPECT_TRUE(err != srs_success);
        EXPECT_TRUE(ERROR_THREAD_DUMMY == srs_error_code(err));
        srs_freep(err);

        err = dc.start();
        EXPECT_TRUE(err != srs_success);
        EXPECT_TRUE(ERROR_THREAD_DUMMY == srs_error_code(err));
        srs_freep(err);
    }
}

class MockCoroutineHandler : public ISrsCoroutineHandler {
public:
    SrsSTCoroutine* trd;
    srs_error_t err;
    srs_cond_t running;
    srs_cond_t exited;
    int cid;
    // Quit without error.
    bool quit;
public:
    MockCoroutineHandler() : trd(NULL), err(srs_success), cid(0), quit(false) {
        running = srs_cond_new();
        exited = srs_cond_new();
    }
    virtual ~MockCoroutineHandler() {
        srs_cond_destroy(running);
        srs_cond_destroy(exited);
    }
public:
    virtual srs_error_t cycle() {
        srs_error_t r0 = srs_success;

        srs_cond_signal(running);
        cid = _srs_context->get_id();

        while (!quit && (r0 = trd->pull()) == srs_success && err == srs_success) {
            srs_usleep(10 * SRS_UTIME_MILLISECONDS);
        }

        srs_cond_signal(exited);

        if (err != srs_success) {
            srs_freep(r0);
            return err;
        }

        return r0;
    }
};

VOID TEST(AppCoroutineTest, StartStop)
{
    if (true) {
        MockCoroutineHandler ch;
        SrsSTCoroutine sc("test", &ch);
        ch.trd = ≻
        EXPECT_EQ(0, sc.cid());

        // Thread stop after created.
        sc.stop();

        EXPECT_EQ(0, sc.cid());

        srs_error_t err = sc.pull();
        EXPECT_TRUE(srs_success != err);
        EXPECT_TRUE(ERROR_THREAD_TERMINATED == srs_error_code(err));
        srs_freep(err);

        // Should never reuse a disposed thread.
        err = sc.start();
        EXPECT_TRUE(srs_success != err);
        EXPECT_TRUE(ERROR_THREAD_DISPOSED == srs_error_code(err));
        srs_freep(err);
    }

    if (true) {
        MockCoroutineHandler ch;
        SrsSTCoroutine sc("test", &ch);
        ch.trd = ≻
        EXPECT_EQ(0, sc.cid());

        EXPECT_TRUE(srs_success == sc.start());
        EXPECT_TRUE(srs_success == sc.pull());

        srs_cond_timedwait(ch.running, 100 * SRS_UTIME_MILLISECONDS);
        EXPECT_TRUE(sc.cid() > 0);

        // Thread stop after started.
        sc.stop();

        srs_error_t err = sc.pull();
        EXPECT_TRUE(srs_success != err);
        EXPECT_TRUE(ERROR_THREAD_INTERRUPED == srs_error_code(err));
        srs_freep(err);

        // Should never reuse a disposed thread.
        err = sc.start();
        EXPECT_TRUE(srs_success != err);
        EXPECT_TRUE(ERROR_THREAD_DISPOSED == srs_error_code(err));
        srs_freep(err);
    }

    if (true) {
        MockCoroutineHandler ch;
        SrsSTCoroutine sc("test", &ch);
        ch.trd = ≻
        EXPECT_EQ(0, sc.cid());

        EXPECT_TRUE(srs_success == sc.start());
        EXPECT_TRUE(srs_success == sc.pull());

        // Error when start multiple times.
        srs_error_t err = sc.start();
        EXPECT_TRUE(srs_success != err);
        EXPECT_TRUE(ERROR_THREAD_STARTED == srs_error_code(err));
        srs_freep(err);

        err = sc.pull();
        EXPECT_TRUE(srs_success != err);
        EXPECT_TRUE(ERROR_THREAD_STARTED == srs_error_code(err));
        srs_freep(err);
    }
}

VOID TEST(AppCoroutineTest, Cycle)
{
    if (true) {
        MockCoroutineHandler ch;
        SrsSTCoroutine sc("test", &ch);
        ch.trd = ≻

        EXPECT_TRUE(srs_success == sc.start());
        EXPECT_TRUE(srs_success == sc.pull());

        // Set cycle to error.
        ch.err = srs_error_new(-1, "cycle");

        srs_cond_timedwait(ch.running, 100 * SRS_UTIME_MILLISECONDS);

        // The cycle error should be pulled.
        srs_error_t err = sc.pull();
        EXPECT_TRUE(srs_success != err);
        EXPECT_TRUE(-1 == srs_error_code(err));
        srs_freep(err);
    }

    if (true) {
        MockCoroutineHandler ch;
        SrsSTCoroutine sc("test", &ch, 250);
        ch.trd = ≻
        EXPECT_EQ(250, sc.cid());

        EXPECT_TRUE(srs_success == sc.start());
        EXPECT_TRUE(srs_success == sc.pull());

        // After running, the cid in cycle should equal to the thread.
        srs_cond_timedwait(ch.running, 100 * SRS_UTIME_MILLISECONDS);
        EXPECT_EQ(250, ch.cid);
    }

    if (true) {
        MockCoroutineHandler ch;
        SrsSTCoroutine sc("test", &ch);
        ch.trd = ≻

        EXPECT_TRUE(srs_success == sc.start());
        EXPECT_TRUE(srs_success == sc.pull());

        srs_cond_timedwait(ch.running, 100 * SRS_UTIME_MILLISECONDS);

        // Interrupt thread, set err to interrupted.
        sc.interrupt();

        // Set cycle to error.
        ch.err = srs_error_new(-1, "cycle");

        // When thread terminated, thread will get its error.
        srs_cond_timedwait(ch.exited, 100 * SRS_UTIME_MILLISECONDS);

        // Override the error by cycle error.
        sc.stop();

        // Should be cycle error.
        srs_error_t err = sc.pull();
        EXPECT_TRUE(srs_success != err);
        EXPECT_TRUE(-1 == srs_error_code(err));
        srs_freep(err);
    }

    if (true) {
        MockCoroutineHandler ch;
        SrsSTCoroutine sc("test", &ch);
        ch.trd = ≻

        EXPECT_TRUE(srs_success == sc.start());
        EXPECT_TRUE(srs_success == sc.pull());

        // Quit without error.
        ch.quit = true;

        // Wait for thread to done.
        srs_cond_timedwait(ch.exited, 100 * SRS_UTIME_MILLISECONDS);

        // Override the error by cycle error.
        sc.stop();

        // Should be cycle error.
        srs_error_t err = sc.pull();
        EXPECT_TRUE(srs_success == err);
        srs_freep(err);
    }
}

void* mock_st_thread_create(void *(*/*start*/)(void *arg), void */*arg*/, int /*joinable*/, int /*stack_size*/) {
    return NULL;
}

VOID TEST(AppCoroutineTest, StartThread)
{
    MockCoroutineHandler ch;
    SrsSTCoroutine sc("test", &ch);
    ch.trd = ≻

    _ST_THREAD_CREATE_PFN ov = _pfn_st_thread_create;
    _pfn_st_thread_create = (_ST_THREAD_CREATE_PFN)mock_st_thread_create;

    srs_error_t err = sc.start();
    _pfn_st_thread_create = ov;

    EXPECT_TRUE(srs_success != err);
    EXPECT_TRUE(ERROR_ST_CREATE_CYCLE_THREAD == srs_error_code(err));
    srs_freep(err);
}

#endif

VOID TEST(AppFragmentTest, CheckDuration)
{
	if (true) {
		SrsFragment frg;
		EXPECT_EQ(-1, frg.start_dts);
		EXPECT_EQ(0, frg.dur);
		EXPECT_FALSE(frg.sequence_header);
	}

	if (true) {
		SrsFragment frg;

		frg.append(0);
		EXPECT_EQ(0, frg.duration());

		frg.append(10);
		EXPECT_EQ(10 * SRS_UTIME_MILLISECONDS, frg.duration());

		frg.append(99);
		EXPECT_EQ(99 * SRS_UTIME_MILLISECONDS, frg.duration());

		frg.append(0x7fffffffLL);
		EXPECT_EQ(0x7fffffffLL * SRS_UTIME_MILLISECONDS, frg.duration());

		frg.append(0xffffffffLL);
		EXPECT_EQ(0xffffffffLL * SRS_UTIME_MILLISECONDS, frg.duration());

		frg.append(0x20c49ba5e353f7LL);
		EXPECT_EQ(0x20c49ba5e353f7LL * SRS_UTIME_MILLISECONDS, frg.duration());
	}

	if (true) {
		SrsFragment frg;

		frg.append(0);
		EXPECT_EQ(0, frg.duration());

		frg.append(0x7fffffffffffffffLL);
		EXPECT_EQ(0, frg.duration());
	}

	if (true) {
		SrsFragment frg;

		frg.append(100);
		EXPECT_EQ(0, frg.duration());

		frg.append(10);
		EXPECT_EQ(0, frg.duration());

		frg.append(100);
		EXPECT_EQ(90 * SRS_UTIME_MILLISECONDS, frg.duration());
	}

	if (true) {
		SrsFragment frg;

		frg.append(-10);
		EXPECT_EQ(0, frg.duration());

		frg.append(-5);
		EXPECT_EQ(0, frg.duration());

		frg.append(10);
		EXPECT_EQ(10 * SRS_UTIME_MILLISECONDS, frg.duration());
	}
}

#define MOCK_LISTEN_PORT 11935

VOID TEST(TCPServerTest, PingPong)
{
}

<|endoftext|>


<commit_before>// Open a FITS file whose primary array represents
// a spectrum (flux vs wavelength)
void FITS_tutorial5()
{
   TVectorD *v;

   printf("\n\n--------------------------------\n");
   printf("WELCOME TO FITS tutorial #5 !!!!\n");
   printf("--------------------------------\n");
   printf("We're gonna open a FITS file that contains a\n");
   printf("table with 9 rows and 8 columns. Column 4 has name\n");
   printf("'mag' and contains a vector of 6 numeric components.\n");
   printf("The values of vectors in rows 1 and 2 (column 4) are:\n");
   printf("Row1: (99.0, 24.768, 23.215, 21.68, 21.076, 20.857)\n");
   printf("Row2: (99.0, 21.689, 20.206, 18.86, 18.32 , 18.128 )\n");
   printf("WARNING: when coding, row and column indices start from 0\n");

   if (!gROOT->IsBatch()) {
      printf("Press ENTER to start..."); getchar();
      printf("\n");
   }

   //Open the table
   TFITSHDU *hdu = new TFITSHDU("sample4.fits[1]");
   if (hdu == 0) {
      printf("ERROR: could not access the HDU\n"); return;
   }

   //Read vectors at rows 1 and 2 (indices 0 and 1)
   TVectorD *vecs[2];
   vecs[0] = hdu->GetTabRealVectorCell(0, "mag");
   vecs[1] = hdu->GetTabRealVectorCell(1, "mag");
   for (int iVec=0; iVec < 2; iVec++) {
      printf("Vector %d = (", iVec+1);
      v = vecs[iVec];
      for(int i=0; i < v->GetNoElements(); i++) {
         if (i>0) printf(", ");
         printf("%lg", (*v)[i]); //NOTE: the asterisk is for using the overloaded [] operator of the TVectorD object
      }
      printf(")\n");
   }

   printf("\nBONUS EXAMPLE: we're gonna dump all rows using\n");
   printf("the function GetTabRealVectorCells()\n");
   printf("Press ENTER to continue..."); getchar();

   TObjArray *vectorCollection = hdu->GetTabRealVectorCells("mag");

   for (int iVec=0; iVec < vectorCollection->GetEntriesFast(); iVec++) {
      printf("Vector %d = (", iVec+1);
      v = (TVectorD *) (*vectorCollection)[iVec]; //NOTE: the asterisk is for using the overloaded [] operator of the TObjArray object
      for(int i=0; i < v->GetNoElements(); i++) {
         if (i>0) printf(", ");
         printf("%lg", (*v)[i]); //NOTE: the asterisk is for using the overloaded [] operator of the TVectorD object
      }
      printf(")\n");
   }

   //Clean up
   delete vecs[0];
   delete vecs[1];
   delete vectorCollection;
   delete hdu;
}

<commit_msg>no more getchar() so auto doc generation does not fail.<commit_after>// Open a FITS file whose primary array represents
// a spectrum (flux vs wavelength)
void FITS_tutorial5()
{
   TVectorD *v;

   printf("\n\n--------------------------------\n");
   printf("WELCOME TO FITS tutorial #5 !!!!\n");
   printf("--------------------------------\n");
   printf("We're gonna open a FITS file that contains a\n");
   printf("table with 9 rows and 8 columns. Column 4 has name\n");
   printf("'mag' and contains a vector of 6 numeric components.\n");
   printf("The values of vectors in rows 1 and 2 (column 4) are:\n");
   printf("Row1: (99.0, 24.768, 23.215, 21.68, 21.076, 20.857)\n");
   printf("Row2: (99.0, 21.689, 20.206, 18.86, 18.32 , 18.128 )\n");
   printf("WARNING: when coding, row and column indices start from 0\n");

   if (!gROOT->IsBatch()) {
      //printf("Press ENTER to start..."); getchar();
      //printf("\n");
   }

   //Open the table
   TFITSHDU *hdu = new TFITSHDU("sample4.fits[1]");
   if (hdu == 0) {
      printf("ERROR: could not access the HDU\n"); return;
   }

   //Read vectors at rows 1 and 2 (indices 0 and 1)
   TVectorD *vecs[2];
   vecs[0] = hdu->GetTabRealVectorCell(0, "mag");
   vecs[1] = hdu->GetTabRealVectorCell(1, "mag");
   for (int iVec=0; iVec < 2; iVec++) {
      printf("Vector %d = (", iVec+1);
      v = vecs[iVec];
      for(int i=0; i < v->GetNoElements(); i++) {
         if (i>0) printf(", ");
         printf("%lg", (*v)[i]); //NOTE: the asterisk is for using the overloaded [] operator of the TVectorD object
      }
      printf(")\n");
   }

   printf("\nBONUS EXAMPLE: we're gonna dump all rows using\n");
   printf("the function GetTabRealVectorCells()\n");
   //printf("Press ENTER to continue..."); getchar();

   TObjArray *vectorCollection = hdu->GetTabRealVectorCells("mag");

   for (int iVec=0; iVec < vectorCollection->GetEntriesFast(); iVec++) {
      printf("Vector %d = (", iVec+1);
      v = (TVectorD *) (*vectorCollection)[iVec]; //NOTE: the asterisk is for using the overloaded [] operator of the TObjArray object
      for(int i=0; i < v->GetNoElements(); i++) {
         if (i>0) printf(", ");
         printf("%lg", (*v)[i]); //NOTE: the asterisk is for using the overloaded [] operator of the TVectorD object
      }
      printf(")\n");
   }

   //Clean up
   delete vecs[0];
   delete vecs[1];
   delete vectorCollection;
   delete hdu;
}

<|endoftext|>


<commit_before>// Copyright 2012 Cloudera Inc.
//
// 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.

#include "util/codec.h"
#include <boost/assign/list_of.hpp>

#include "util/compress.h"
#include "util/decompress.h"

#include "gen-cpp/Descriptors_types.h"
#include "gen-cpp/Descriptors_constants.h"

using namespace std;
using namespace boost;
using namespace boost::assign;
using namespace impala;

const char* const Codec::DEFAULT_COMPRESSION =
     "org.apache.hadoop.io.compress.DefaultCodec";

const char* const Codec::GZIP_COMPRESSION =
     "org.apache.hadoop.io.compress.GzipCodec";

const char* const Codec::BZIP2_COMPRESSION =
     "org.apache.hadoop.io.compress.BZip2Codec";

const char* const Codec::SNAPPY_COMPRESSION =
     "org.apache.hadoop.io.compress.SnappyCodec";

const Codec::CodecMap Codec::CODEC_MAP = map_list_of
  ("", THdfsCompression::NONE)
  (Codec::DEFAULT_COMPRESSION, THdfsCompression::DEFAULT)
  (Codec::GZIP_COMPRESSION, THdfsCompression::GZIP)
  (Codec::BZIP2_COMPRESSION, THdfsCompression::BZIP2)
  (Codec::SNAPPY_COMPRESSION, THdfsCompression::SNAPPY_BLOCKED);

string Codec::GetCodecName(THdfsCompression::type type) {
  map<const string, THdfsCompression::type>::const_iterator im;
  for (im = g_Descriptors_constants.COMPRESSION_MAP.begin();
       im != g_Descriptors_constants.COMPRESSION_MAP.end(); ++im) {
    if (im->second == type) return im->first;
  }
  DCHECK(im != g_Descriptors_constants.COMPRESSION_MAP.end());
  return "INVALID";
}

Status Codec::CreateCompressor(RuntimeState* runtime_state, MemPool* mem_pool,
                               bool reuse, const string& codec,
                               scoped_ptr<Codec>* compressor) {
  map<const string, const THdfsCompression::type>::const_iterator
      type = CODEC_MAP.find(codec);

  if (type == CODEC_MAP.end()) {
    stringstream ss;
    ss << "Unknown Codec: " << codec;
    return Status(ss.str());
  }
  Codec* comp;
  RETURN_IF_ERROR(
      CreateCompressor(runtime_state, mem_pool, reuse, type->second, &comp));
  compressor->reset(comp);
  return Status::OK;
}

Status Codec::CreateCompressor(RuntimeState* runtime_state, MemPool* mem_pool,
                               bool reuse, THdfsCompression::type format,
                               scoped_ptr<Codec>* compressor) {
  Codec* comp;
  RETURN_IF_ERROR(
      CreateCompressor(runtime_state, mem_pool, reuse, format, &comp));
  compressor->reset(comp);
  return Status::OK;
}

Status Codec::CreateCompressor(RuntimeState* runtime_state, MemPool* mem_pool,
                               bool reuse, THdfsCompression::type format,
                               Codec** compressor) {
  switch (format) {
    case THdfsCompression::NONE:
      *compressor = NULL;
      return Status::OK;
    case THdfsCompression::GZIP:
      *compressor = new GzipCompressor(GzipCompressor::GZIP, mem_pool, reuse);
      break;
    case THdfsCompression::DEFAULT:
      *compressor = new GzipCompressor(GzipCompressor::ZLIB, mem_pool, reuse);
      break;
    case THdfsCompression::DEFLATE:
      *compressor = new GzipCompressor(GzipCompressor::DEFLATE, mem_pool, reuse);
      break;
    case THdfsCompression::BZIP2:
      *compressor = new BzipCompressor(mem_pool, reuse);
      break;
    case THdfsCompression::SNAPPY_BLOCKED:
      *compressor = new SnappyBlockCompressor(mem_pool, reuse);
      break;
    case THdfsCompression::SNAPPY:
      *compressor = new SnappyCompressor(mem_pool, reuse);
      break;
  }

  return (*compressor)->Init();
}

Status Codec::CreateDecompressor(RuntimeState* runtime_state, MemPool* mem_pool,
                                 bool reuse, const string& codec,
                                 scoped_ptr<Codec>* decompressor) {
  map<const string, const THdfsCompression::type>::const_iterator
      type = CODEC_MAP.find(codec);

  if (type == CODEC_MAP.end()) {
    stringstream ss;
    ss << "Unknown Codec: " << codec;
    return Status(ss.str());
  }
  Codec* decom;
  RETURN_IF_ERROR(
      CreateDecompressor(runtime_state, mem_pool, reuse, type->second, &decom));
  decompressor->reset(decom);
  return Status::OK;
}

Status Codec::CreateDecompressor(RuntimeState* runtime_state, MemPool* mem_pool,
                                 bool reuse, THdfsCompression::type format,
                                 scoped_ptr<Codec>* decompressor) {
  Codec* decom;
  RETURN_IF_ERROR(
      CreateDecompressor(runtime_state, mem_pool, reuse, format, &decom));
  decompressor->reset(decom);
  return Status::OK;
}

Status Codec::CreateDecompressor(RuntimeState* runtime_state, MemPool* mem_pool,
                                 bool reuse, THdfsCompression::type format,
                                 Codec** decompressor) {
  switch (format) {
    case THdfsCompression::NONE:
      *decompressor = NULL;
      return Status::OK;
    case THdfsCompression::DEFAULT:
    case THdfsCompression::GZIP:
      *decompressor = new GzipDecompressor(mem_pool, reuse, false);
      break;
    case THdfsCompression::DEFLATE:
      *decompressor = new GzipDecompressor(mem_pool, reuse, true);
      break;
    case THdfsCompression::BZIP2:
      *decompressor = new BzipDecompressor(mem_pool, reuse);
      break;
    case THdfsCompression::SNAPPY_BLOCKED:
      *decompressor = new SnappyBlockDecompressor(mem_pool, reuse);
      break;
    case THdfsCompression::SNAPPY:
      *decompressor = new SnappyDecompressor(mem_pool, reuse);
      break;
  }

  return (*decompressor)->Init();
}

Codec::Codec(MemPool* mem_pool, bool reuse_buffer)
  : memory_pool_(mem_pool),
    reuse_buffer_(reuse_buffer),
    out_buffer_(NULL),
    buffer_length_(0) {
}

<commit_msg>Make unsupported codec message a little clearer.<commit_after>// Copyright 2012 Cloudera Inc.
//
// 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.

#include "util/codec.h"
#include <boost/assign/list_of.hpp>

#include "util/compress.h"
#include "util/decompress.h"

#include "gen-cpp/Descriptors_types.h"
#include "gen-cpp/Descriptors_constants.h"

using namespace std;
using namespace boost;
using namespace boost::assign;
using namespace impala;

const char* const Codec::DEFAULT_COMPRESSION =
    "org.apache.hadoop.io.compress.DefaultCodec";

const char* const Codec::GZIP_COMPRESSION =
    "org.apache.hadoop.io.compress.GzipCodec";

const char* const Codec::BZIP2_COMPRESSION =
    "org.apache.hadoop.io.compress.BZip2Codec";

const char* const Codec::SNAPPY_COMPRESSION =
    "org.apache.hadoop.io.compress.SnappyCodec";

const char* const UNKNOWN_CODEC_ERROR =
    "This compression codec is currently unsupported: ";

const Codec::CodecMap Codec::CODEC_MAP = map_list_of
  ("", THdfsCompression::NONE)
  (Codec::DEFAULT_COMPRESSION, THdfsCompression::DEFAULT)
  (Codec::GZIP_COMPRESSION, THdfsCompression::GZIP)
  (Codec::BZIP2_COMPRESSION, THdfsCompression::BZIP2)
  (Codec::SNAPPY_COMPRESSION, THdfsCompression::SNAPPY_BLOCKED);

string Codec::GetCodecName(THdfsCompression::type type) {
  map<const string, THdfsCompression::type>::const_iterator im;
  for (im = g_Descriptors_constants.COMPRESSION_MAP.begin();
       im != g_Descriptors_constants.COMPRESSION_MAP.end(); ++im) {
    if (im->second == type) return im->first;
  }
  DCHECK(im != g_Descriptors_constants.COMPRESSION_MAP.end());
  return "INVALID";
}

Status Codec::CreateCompressor(RuntimeState* runtime_state, MemPool* mem_pool,
                               bool reuse, const string& codec,
                               scoped_ptr<Codec>* compressor) {
  map<const string, const THdfsCompression::type>::const_iterator
      type = CODEC_MAP.find(codec);

  if (type == CODEC_MAP.end()) {
    stringstream ss;
    ss << UNKNOWN_CODEC_ERROR << codec;
    return Status(ss.str());
  }
  Codec* comp;
  RETURN_IF_ERROR(
      CreateCompressor(runtime_state, mem_pool, reuse, type->second, &comp));
  compressor->reset(comp);
  return Status::OK;
}

Status Codec::CreateCompressor(RuntimeState* runtime_state, MemPool* mem_pool,
                               bool reuse, THdfsCompression::type format,
                               scoped_ptr<Codec>* compressor) {
  Codec* comp;
  RETURN_IF_ERROR(
      CreateCompressor(runtime_state, mem_pool, reuse, format, &comp));
  compressor->reset(comp);
  return Status::OK;
}

Status Codec::CreateCompressor(RuntimeState* runtime_state, MemPool* mem_pool,
                               bool reuse, THdfsCompression::type format,
                               Codec** compressor) {
  switch (format) {
    case THdfsCompression::NONE:
      *compressor = NULL;
      return Status::OK;
    case THdfsCompression::GZIP:
      *compressor = new GzipCompressor(GzipCompressor::GZIP, mem_pool, reuse);
      break;
    case THdfsCompression::DEFAULT:
      *compressor = new GzipCompressor(GzipCompressor::ZLIB, mem_pool, reuse);
      break;
    case THdfsCompression::DEFLATE:
      *compressor = new GzipCompressor(GzipCompressor::DEFLATE, mem_pool, reuse);
      break;
    case THdfsCompression::BZIP2:
      *compressor = new BzipCompressor(mem_pool, reuse);
      break;
    case THdfsCompression::SNAPPY_BLOCKED:
      *compressor = new SnappyBlockCompressor(mem_pool, reuse);
      break;
    case THdfsCompression::SNAPPY:
      *compressor = new SnappyCompressor(mem_pool, reuse);
      break;
  }

  return (*compressor)->Init();
}

Status Codec::CreateDecompressor(RuntimeState* runtime_state, MemPool* mem_pool,
                                 bool reuse, const string& codec,
                                 scoped_ptr<Codec>* decompressor) {
  map<const string, const THdfsCompression::type>::const_iterator
      type = CODEC_MAP.find(codec);

  if (type == CODEC_MAP.end()) {
    stringstream ss;
    ss << UNKNOWN_CODEC_ERROR << codec;
    return Status(ss.str());
  }
  Codec* decom;
  RETURN_IF_ERROR(
      CreateDecompressor(runtime_state, mem_pool, reuse, type->second, &decom));
  decompressor->reset(decom);
  return Status::OK;
}

Status Codec::CreateDecompressor(RuntimeState* runtime_state, MemPool* mem_pool,
                                 bool reuse, THdfsCompression::type format,
                                 scoped_ptr<Codec>* decompressor) {
  Codec* decom;
  RETURN_IF_ERROR(
      CreateDecompressor(runtime_state, mem_pool, reuse, format, &decom));
  decompressor->reset(decom);
  return Status::OK;
}

Status Codec::CreateDecompressor(RuntimeState* runtime_state, MemPool* mem_pool,
                                 bool reuse, THdfsCompression::type format,
                                 Codec** decompressor) {
  switch (format) {
    case THdfsCompression::NONE:
      *decompressor = NULL;
      return Status::OK;
    case THdfsCompression::DEFAULT:
    case THdfsCompression::GZIP:
      *decompressor = new GzipDecompressor(mem_pool, reuse, false);
      break;
    case THdfsCompression::DEFLATE:
      *decompressor = new GzipDecompressor(mem_pool, reuse, true);
      break;
    case THdfsCompression::BZIP2:
      *decompressor = new BzipDecompressor(mem_pool, reuse);
      break;
    case THdfsCompression::SNAPPY_BLOCKED:
      *decompressor = new SnappyBlockDecompressor(mem_pool, reuse);
      break;
    case THdfsCompression::SNAPPY:
      *decompressor = new SnappyDecompressor(mem_pool, reuse);
      break;
  }

  return (*decompressor)->Init();
}

Codec::Codec(MemPool* mem_pool, bool reuse_buffer)
  : memory_pool_(mem_pool),
    reuse_buffer_(reuse_buffer),
    out_buffer_(NULL),
    buffer_length_(0) {
}

<|endoftext|>