<commit_before>#include "qrwidgetdemo.h"
#include "ui_qrwidgetdemo.h"

#include "toast/qrtoastdemo.h"
#include "waitingspinner/waitingspinnerwidget.h"
#include "emailinputter/emailinputterwidget.h"

QrWidgetDemo::QrWidgetDemo(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::QrWidgetDemo)
{
    ui->setupUi(this);

    auto widgetDoModelFunc = [this](QWidget *widget){
        QEventLoop eventloop;
        QObject::connect(widget, &QWidget::destroyed,
                         &eventloop, &QEventLoop::quit);
        eventloop.exec();
    };

    connect(ui->waitingspinner, &QPushButton::clicked, [this, widgetDoModelFunc](){
        WaitingSpinnerWidget waitingspinner;
        waitingspinner.setAttribute( Qt::WA_DeleteOnClose );
        waitingspinner.show();

        widgetDoModelFunc(&waitingspinner);
    });
    connect(ui->emailinputter, &QPushButton::clicked, [this, widgetDoModelFunc](){
        EmailInputterWidget emailInputter;
        emailInputter.show();

        widgetDoModelFunc(&emailInputter);

    });
    connect(ui->toast, &QPushButton::clicked, [this, widgetDoModelFunc](){
        QrToastDemo toastDemo;
        toastDemo.show();

        widgetDoModelFunc(&toastDemo);
    });
}

QrWidgetDemo::~QrWidgetDemo()
{
    delete ui;
}
<commit_msg>runtime error<commit_after>#include "qrwidgetdemo.h"
#include "ui_qrwidgetdemo.h"

#include "toast/qrtoastdemo.h"
#include "waitingspinner/waitingspinnerwidget.h"
#include "emailinputter/emailinputterwidget.h"

QrWidgetDemo::QrWidgetDemo(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::QrWidgetDemo)
{
    ui->setupUi(this);

    auto widgetDoModelFunc = [this](QWidget *widget){
        QEventLoop eventloop;
        QObject::connect(widget, &QWidget::destroyed,
                         &eventloop, &QEventLoop::quit);
        eventloop.exec();
    };

    connect(ui->waitingspinner, &QPushButton::clicked, [this, widgetDoModelFunc](){
        WaitingSpinnerWidget waitingspinner;
//        waitingspinner.setAttribute( Qt::WA_DeleteOnClose );
        waitingspinner.show();

        widgetDoModelFunc(&waitingspinner);
    });
    connect(ui->emailinputter, &QPushButton::clicked, [this, widgetDoModelFunc](){
        EmailInputterWidget emailInputter;
        emailInputter.show();

        widgetDoModelFunc(&emailInputter);

    });
    connect(ui->toast, &QPushButton::clicked, [this, widgetDoModelFunc](){
        QrToastDemo toastDemo;
        toastDemo.show();

        widgetDoModelFunc(&toastDemo);
    });
}

QrWidgetDemo::~QrWidgetDemo()
{
    delete ui;
}
<|endoftext|>


<commit_before>/* -*- mode:C++; -*- */
/* MIT License -- MyThOS: The Many-Threads Operating System
 *
 * 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.
 *
 * Copyright 2014 Randolf Rotta, Maik Krüger, and contributors, BTU Cottbus-Senftenberg
 */

#include <cstddef>
#include <cstdint>
#include <stdlib.h>
#include <cstdarg>
#include <endian.h>
#include <pthread.h>
#include <atomic>
#include <sys/types.h>
#include <errno.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/resource.h>

#include "mythos/syscall.hh"
#include "runtime/mlog.hh"
#include "util/elf64.hh"
#include "runtime/ExecutionContext.hh"
#include "runtime/Portal.hh"
#include "runtime/ExecutionContext.hh"
#include "runtime/CapMap.hh"
#include "runtime/Example.hh"
#include "runtime/PageMap.hh"
#include "runtime/KernelMemory.hh"
#include "runtime/SimpleCapAlloc.hh"
#include "runtime/tls.hh"
#include "runtime/futex.hh"

extern mythos::InvocationBuf* msg_ptr asm("msg_ptr");
extern mythos::Portal portal;
extern mythos::CapMap myCS;
extern mythos::PageMap myAS;
extern mythos::KernelMemory kmem;
extern mythos::SimpleCapAllocDel capAlloc;

#define NUM_CPUS (3)

extern "C" [[noreturn]] void __assert_fail (const char *expr, const char *file, int line, const char *func)
{
    mlog::Logger<> logassert("assert");
    logassert.error("ASSERT",expr,"failed in",file,":",line,func);
    mythos::syscall_exit(-1); /// @TODO syscall_abort(); to see some stack backtrace etc
}

struct iovec
{
    const char* io_base;
    size_t iov_len;
};

ssize_t writev(int fd, const struct iovec *iov, int iovcnt)
{
    //MLOG_WARN(mlog::app, "syscall writev");
    ssize_t ret = 0;
    for (int i = 0; i < iovcnt; i++) {
        mlog::sink->write(iov[i].io_base, iov[i].iov_len);
        ret += iov[i].iov_len;
    }
    return ret;
}

int prlimit(
    pid_t pid, int resource, const struct rlimit *new_limit,
    struct rlimit *old_limit)
{
    // dummy implementation
}

int sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask)
{
    MLOG_ERROR(mlog::app, "syscall sched_setaffinity", DVAR(pid), DVAR(cpusetsize), DVARhex(mask));
    if(cpusetsize == NUM_CPUS && mask == NULL) return -EFAULT;
    return 0;
}

int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask)
{
    MLOG_ERROR(mlog::app, "syscall sched_getaffinity", DVAR(pid), DVAR(cpusetsize), DVARhex(mask));
    if (mask) {
        CPU_ZERO(mask);
        for(int i = 0; i < NUM_CPUS; i++) CPU_SET(i, mask);
    }
    return NUM_CPUS;
}

extern "C" long mythos_musl_syscall(
    long num, long a1, long a2, long a3,
    long a4, long a5, long a6)
{
    //MLOG_DETAIL(mlog::app, "mythos_musl_syscall", DVAR(num),
    //DVAR(a1), DVAR(a2), DVAR(a3),
    //DVAR(a4), DVAR(a5), DVAR(a6));
    // see http://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/
    switch (num) {
    case 13: // rt_sigaction
        MLOG_ERROR(mlog::app, "syscall rt_sigaction NYI");
        return 0;
    case 14: // rt_sigprocmask(how, set, oldset, sigsetsize)
        MLOG_ERROR(mlog::app, "syscall rt_sigprocmask NYI");
        return 0;
    case 16: // ioctl
        MLOG_ERROR(mlog::app, "syscall ioctl NYI");
        return 0;
    case 20: // writev(fd, *iov, iovcnt)
        //MLOG_ERROR(mlog::app, "syscall writev NYI");
        return writev(a1, reinterpret_cast<const struct iovec *>(a2), a3);
    case 24: // sched_yield
        MLOG_ERROR(mlog::app, "syscall sched_yield NYI");
        return 0;
    case 39: // getpid
        MLOG_ERROR(mlog::app, "syscall getpid NYI");
        return 0;
    case 60: // exit(exit_code)
        MLOG_DETAIL(mlog::app, "syscall exit", DVAR(a1));
        asm volatile ("syscall" : : "D"(0), "S"(a1) : "memory");
        return 0;
    case 200: // tkill(pid, sig)
        MLOG_ERROR(mlog::app, "syscall tkill NYI");
        return 0;
    case 202: // sys_futex
        MLOG_DETAIL(mlog::app, "syscall futex");
        {
            uint32_t val2 = 0;
            return do_futex(reinterpret_cast<uint32_t*>(a1) /*uaddr*/,
                            a2 /*op*/, a3 /*val*/, nullptr/* timeout*/,
                            nullptr /*uaddr2*/, val2/*val2*/, a6/*val3*/);
        }
    case 203: // sched_setaffinity
        return sched_setaffinity(a1, a2, reinterpret_cast<cpu_set_t*>(a3));
    case 204: // sched_getaffinity
        return sched_getaffinity(a1, a2, reinterpret_cast<cpu_set_t*>(a3));
    case 228: // clock_gettime
        MLOG_ERROR(mlog::app, "syscall clock_gettime NYI");
        return 0;
    case 231: // exit_group for all pthreads
        MLOG_ERROR(mlog::app, "syscall exit_group NYI");
        return 0;
    case 302: // prlimit64
        MLOG_ERROR(mlog::app, "syscall prlimit64 NYI", DVAR(a1), DVAR(a2), DVAR(a3), DVAR(a4), DVAR(a5), DVAR(a6));
        return 1;
    default:
        MLOG_ERROR(mlog::app, "Error: mythos_musl_syscall NYI", DVAR(num),
            DVAR(a1), DVAR(a2), DVAR(a3),
            DVAR(a4), DVAR(a5), DVAR(a6));
    }
    return -1;
}

extern "C" void * mmap(void *start, size_t len, int prot, int flags, int fd, off_t off)
{
    // dummy implementation
    MLOG_DETAIL(mlog::app, "mmap");
    if (fd == -1) return malloc(len);
    errno = ENOMEM;
    return MAP_FAILED;
}

extern "C" int munmap(void *start, size_t len)
{
    // dummy implementation
    MLOG_DETAIL(mlog::app, "munmap");
    return 0;
}

extern "C" int unmapself(void *start, size_t len)
{
    // dummy implementation
    MLOG_DETAIL(mlog::app, "unmapself");
    while(1);
    return 0;
}

extern "C" int mprotect(void *addr, size_t len, int prot)
{
    // dummy implementation
    MLOG_DETAIL(mlog::app, "mprotect");
    //size_t start, end;
    //start = (size_t)addr & -PAGE_SIZE;
    //end = (size_t)((char *)addr + len + PAGE_SIZE-1) & -PAGE_SIZE;
    return 0;
}

int myclone(
    int (*func)(void *), void *stack, int flags,
    void *arg, int* ptid, void* tls, int* ctid)
{
    MLOG_DETAIL(mlog::app, "myclone");
    ASSERT(tls != nullptr);

    mythos::PortalLock pl(portal); // future access will fail if the portal is in use already
    mythos::ExecutionContext ec(capAlloc());
    if (ptid && (flags&CLONE_PARENT_SETTID)) *ptid = int(ec.cap());
    // @todo store thread-specific ctid pointer, which should set to 0 by the OS on the thread's exit
    // @todo needs interaction with a process internal scheduler or core manager in order to figure out where to schedule the new thread
    auto res1 = ec.create(kmem).as(myAS).cs(myCS).sched(mythos::init::SCHEDULERS_START + 1)
        .prepareStack(stack).startFunInt(func, arg, ec.cap())
        .suspended(false).fs(tls)
        .invokeVia(pl).wait();
    MLOG_DETAIL(mlog::app, DVAR(ec.cap()));
    return ec.cap();
}

extern "C" int clone(int (*func)(void *), void *stack, int flags, void *arg, ...)
{
    MLOG_DETAIL(mlog::app, "clone wrapper");
    va_list args;
    va_start(args, arg);
    int* ptid = va_arg(args, int*);
    void* tls = va_arg(args, void*);
    int* ctid = va_arg(args, int*);
    va_end(args);
    return myclone(func, stack, flags, arg, ptid, tls, ctid);
}

struct dl_phdr_info
{
    void* dlpi_addr; /* Base address of object */
    const char* dlpi_name; /* (Null-terminated) name of object */
    const void* dlpi_phdr; /* Pointer to array of ELF program headers for this object */
    uint16_t dlpi_phnum; /* # of items in dlpi_phdr */
};

extern char __executable_start; //< provided by the default linker script

/** walk through list of shared objects.
 * http://man7.org/linux/man-pages/man3/dl_iterate_phdr.3.html
 * https://github.com/ensc/dietlibc/blob/master/libcruft/dl_iterate_phdr.c
 *
 * WARNING: use --eh-frame-hdr linker flag to ensure the presence of the EH_FRAME segment!
 */
extern "C" int dl_iterate_phdr(
    int (*callback) (dl_phdr_info *info, size_t size, void *data), void *data)
{
    MLOG_ERROR(mlog::app, "dl_iterate_phdr", DVAR((void*)callback), DVAR(&__executable_start));
    mythos::elf64::Elf64Image img(&__executable_start);
    ASSERT(img.isValid());

    // HACK this assumes llvm libunwind
    // the targetAddr contains the instruction pointer where the exception was thrown
    struct dl_iterate_cb_data {
        void *addressSpace;
        void *sects;
        void *targetAddr;
    };
    auto cbdata = static_cast<dl_iterate_cb_data *>(data);
    MLOG_ERROR(mlog::app, "dl_iterate_phdr", DVAR(cbdata->addressSpace),
        DVAR(cbdata->sects), DVAR(cbdata->targetAddr));

    dl_phdr_info info;
    info.dlpi_addr = 0; // callback ignores this header if its target addr is smaller than this.
    info.dlpi_name = "init.elf";
    info.dlpi_phdr = (const void*)img.phdr(0);
    info.dlpi_phnum = img.phnum();
    auto res = (*callback) (&info, sizeof(info), data);
    return res;
}
<commit_msg>fixed getaffinity<commit_after>/* -*- mode:C++; -*- */
/* MIT License -- MyThOS: The Many-Threads Operating System
 *
 * 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.
 *
 * Copyright 2014 Randolf Rotta, Maik Krüger, and contributors, BTU Cottbus-Senftenberg
 */

#include <cstddef>
#include <cstdint>
#include <stdlib.h>
#include <cstdarg>
#include <endian.h>
#include <pthread.h>
#include <atomic>
#include <sys/types.h>
#include <errno.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <string.h>

#include "mythos/syscall.hh"
#include "runtime/mlog.hh"
#include "util/elf64.hh"
#include "runtime/ExecutionContext.hh"
#include "runtime/Portal.hh"
#include "runtime/ExecutionContext.hh"
#include "runtime/CapMap.hh"
#include "runtime/Example.hh"
#include "runtime/PageMap.hh"
#include "runtime/KernelMemory.hh"
#include "runtime/SimpleCapAlloc.hh"
#include "runtime/tls.hh"
#include "runtime/futex.hh"

extern mythos::InvocationBuf* msg_ptr asm("msg_ptr");
extern mythos::Portal portal;
extern mythos::CapMap myCS;
extern mythos::PageMap myAS;
extern mythos::KernelMemory kmem;
extern mythos::SimpleCapAllocDel capAlloc;

#define NUM_CPUS (3)

extern "C" [[noreturn]] void __assert_fail (const char *expr, const char *file, int line, const char *func)
{
    mlog::Logger<> logassert("assert");
    logassert.error("ASSERT",expr,"failed in",file,":",line,func);
    mythos::syscall_exit(-1); /// @TODO syscall_abort(); to see some stack backtrace etc
}

struct iovec
{
    const char* io_base;
    size_t iov_len;
};

ssize_t writev(int fd, const struct iovec *iov, int iovcnt)
{
    //MLOG_WARN(mlog::app, "syscall writev");
    ssize_t ret = 0;
    for (int i = 0; i < iovcnt; i++) {
        mlog::sink->write(iov[i].io_base, iov[i].iov_len);
        ret += iov[i].iov_len;
    }
    return ret;
}

int prlimit(
    pid_t pid, int resource, const struct rlimit *new_limit,
    struct rlimit *old_limit)
{
    // dummy implementation
}

int sched_setaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask)
{
    MLOG_ERROR(mlog::app, "syscall sched_setaffinity", DVAR(pid), DVAR(cpusetsize), DVARhex(mask));
    if(cpusetsize == NUM_CPUS && mask == NULL) return -EFAULT;
    return 0;
}

int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask)
{
    MLOG_ERROR(mlog::app, "syscall sched_getaffinity", DVAR(pid), DVAR(cpusetsize), DVARhex(mask));
    if (mask) {
        //CPU_ZERO(mask);
	memset(mask, 0, cpusetsize);
        for(int i = 0; i < NUM_CPUS; i++) CPU_SET(i, mask);
    }
    return NUM_CPUS;
}

extern "C" long mythos_musl_syscall(
    long num, long a1, long a2, long a3,
    long a4, long a5, long a6)
{
    //MLOG_DETAIL(mlog::app, "mythos_musl_syscall", DVAR(num),
    //DVAR(a1), DVAR(a2), DVAR(a3),
    //DVAR(a4), DVAR(a5), DVAR(a6));
    // see http://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/
    switch (num) {
    case 13: // rt_sigaction
        MLOG_ERROR(mlog::app, "syscall rt_sigaction NYI");
        return 0;
    case 14: // rt_sigprocmask(how, set, oldset, sigsetsize)
        MLOG_ERROR(mlog::app, "syscall rt_sigprocmask NYI");
        return 0;
    case 16: // ioctl
        MLOG_ERROR(mlog::app, "syscall ioctl NYI");
        return 0;
    case 20: // writev(fd, *iov, iovcnt)
        //MLOG_ERROR(mlog::app, "syscall writev NYI");
        return writev(a1, reinterpret_cast<const struct iovec *>(a2), a3);
    case 24: // sched_yield
        MLOG_ERROR(mlog::app, "syscall sched_yield NYI");
        return 0;
    case 39: // getpid
        MLOG_ERROR(mlog::app, "syscall getpid NYI");
        return 0;
    case 60: // exit(exit_code)
        MLOG_DETAIL(mlog::app, "syscall exit", DVAR(a1));
        asm volatile ("syscall" : : "D"(0), "S"(a1) : "memory");
        return 0;
    case 200: // tkill(pid, sig)
        MLOG_ERROR(mlog::app, "syscall tkill NYI");
        return 0;
    case 202: // sys_futex
        MLOG_DETAIL(mlog::app, "syscall futex");
        {
            uint32_t val2 = 0;
            return do_futex(reinterpret_cast<uint32_t*>(a1) /*uaddr*/,
                            a2 /*op*/, a3 /*val*/, nullptr/* timeout*/,
                            nullptr /*uaddr2*/, val2/*val2*/, a6/*val3*/);
        }
    case 203: // sched_setaffinity
        return sched_setaffinity(a1, a2, reinterpret_cast<cpu_set_t*>(a3));
    case 204: // sched_getaffinity
        return sched_getaffinity(a1, a2, reinterpret_cast<cpu_set_t*>(a3));
    case 228: // clock_gettime
        MLOG_ERROR(mlog::app, "syscall clock_gettime NYI");
        return 0;
    case 231: // exit_group for all pthreads
        MLOG_ERROR(mlog::app, "syscall exit_group NYI");
        return 0;
    case 302: // prlimit64
        MLOG_ERROR(mlog::app, "syscall prlimit64 NYI", DVAR(a1), DVAR(a2), DVAR(a3), DVAR(a4), DVAR(a5), DVAR(a6));
        return 1;
    default:
        MLOG_ERROR(mlog::app, "Error: mythos_musl_syscall NYI", DVAR(num),
            DVAR(a1), DVAR(a2), DVAR(a3),
            DVAR(a4), DVAR(a5), DVAR(a6));
    }
    return -1;
}

extern "C" void * mmap(void *start, size_t len, int prot, int flags, int fd, off_t off)
{
    // dummy implementation
    MLOG_DETAIL(mlog::app, "mmap");
    if (fd == -1) return malloc(len);
    errno = ENOMEM;
    return MAP_FAILED;
}

extern "C" int munmap(void *start, size_t len)
{
    // dummy implementation
    MLOG_DETAIL(mlog::app, "munmap");
    return 0;
}

extern "C" int unmapself(void *start, size_t len)
{
    // dummy implementation
    MLOG_DETAIL(mlog::app, "unmapself");
    while(1);
    return 0;
}

extern "C" int mprotect(void *addr, size_t len, int prot)
{
    // dummy implementation
    MLOG_DETAIL(mlog::app, "mprotect");
    //size_t start, end;
    //start = (size_t)addr & -PAGE_SIZE;
    //end = (size_t)((char *)addr + len + PAGE_SIZE-1) & -PAGE_SIZE;
    return 0;
}

int myclone(
    int (*func)(void *), void *stack, int flags,
    void *arg, int* ptid, void* tls, int* ctid)
{
    MLOG_DETAIL(mlog::app, "myclone");
    ASSERT(tls != nullptr);

    mythos::PortalLock pl(portal); // future access will fail if the portal is in use already
    mythos::ExecutionContext ec(capAlloc());
    if (ptid && (flags&CLONE_PARENT_SETTID)) *ptid = int(ec.cap());
    // @todo store thread-specific ctid pointer, which should set to 0 by the OS on the thread's exit
    // @todo needs interaction with a process internal scheduler or core manager in order to figure out where to schedule the new thread
    auto res1 = ec.create(kmem).as(myAS).cs(myCS).sched(mythos::init::SCHEDULERS_START + 1)
        .prepareStack(stack).startFunInt(func, arg, ec.cap())
        .suspended(false).fs(tls)
        .invokeVia(pl).wait();
    MLOG_DETAIL(mlog::app, DVAR(ec.cap()));
    return ec.cap();
}

extern "C" int clone(int (*func)(void *), void *stack, int flags, void *arg, ...)
{
    MLOG_DETAIL(mlog::app, "clone wrapper");
    va_list args;
    va_start(args, arg);
    int* ptid = va_arg(args, int*);
    void* tls = va_arg(args, void*);
    int* ctid = va_arg(args, int*);
    va_end(args);
    return myclone(func, stack, flags, arg, ptid, tls, ctid);
}

struct dl_phdr_info
{
    void* dlpi_addr; /* Base address of object */
    const char* dlpi_name; /* (Null-terminated) name of object */
    const void* dlpi_phdr; /* Pointer to array of ELF program headers for this object */
    uint16_t dlpi_phnum; /* # of items in dlpi_phdr */
};

extern char __executable_start; //< provided by the default linker script

/** walk through list of shared objects.
 * http://man7.org/linux/man-pages/man3/dl_iterate_phdr.3.html
 * https://github.com/ensc/dietlibc/blob/master/libcruft/dl_iterate_phdr.c
 *
 * WARNING: use --eh-frame-hdr linker flag to ensure the presence of the EH_FRAME segment!
 */
extern "C" int dl_iterate_phdr(
    int (*callback) (dl_phdr_info *info, size_t size, void *data), void *data)
{
    MLOG_ERROR(mlog::app, "dl_iterate_phdr", DVAR((void*)callback), DVAR(&__executable_start));
    mythos::elf64::Elf64Image img(&__executable_start);
    ASSERT(img.isValid());

    // HACK this assumes llvm libunwind
    // the targetAddr contains the instruction pointer where the exception was thrown
    struct dl_iterate_cb_data {
        void *addressSpace;
        void *sects;
        void *targetAddr;
    };
    auto cbdata = static_cast<dl_iterate_cb_data *>(data);
    MLOG_ERROR(mlog::app, "dl_iterate_phdr", DVAR(cbdata->addressSpace),
        DVAR(cbdata->sects), DVAR(cbdata->targetAddr));

    dl_phdr_info info;
    info.dlpi_addr = 0; // callback ignores this header if its target addr is smaller than this.
    info.dlpi_name = "init.elf";
    info.dlpi_phdr = (const void*)img.phdr(0);
    info.dlpi_phnum = img.phnum();
    auto res = (*callback) (&info, sizeof(info), data);
    return res;
}
<|endoftext|>


<commit_before>
#ifndef MANAGER_HPP_
#define MANAGER_HPP_

#include <vector>			 // vector
#include <random>            // mt19937, uniform_int_distribution, random_device
#include <pthread.h>		 // pthreads
#include <utility>			 // make_pair

#include "Chromosome.hpp"
#include "RouletteWheel.hpp"
#include "SafeQueue.hpp"

template <class T>
class Manager {
protected:

	unsigned int population_size;
	unsigned int chromosome_size;

	unsigned int max_generation_number;

	T max_chromosome_value;
	T min_chromosome_value;

	bool use_self_adaptive;
	double mutation_rate;
	double mutation_change_rate;
	double similarity_index;

	// TODO check if clonning rate is by convention (1 - (mutation_rate + crossover)).
	//double clonning_rate;

	double crossover_rate;

	std::vector<Chromosome<T > > population;

	// Need to have some way of ensure no duplication of solutions
	std::vector<Chromosome<T > > solutions;

	RouletteWheel rw;
	//RouletteWheel op_roulettewheel;

	SafeQueue<unsigned int > safe_queue;
	SafeQueue<std::pair<unsigned int, double > > result_queue;

	std::vector<pthread_t > threadpool;

	std::mt19937 rand_engine;
	std::uniform_real_distribution<float> op_dist;
	std::uniform_real_distribution<float> mutation_dist;
	//std::uniform_int_distribution<int> chrom_dist;

	// With this we can limit the number of threads used
	unsigned int max_num_threads;
	unsigned int num_threads_used;

	// Library flags
	int number_of_nodes = 0;
	int number_of_threads = 5;

	// Fitness function
	double (*fitness_function)(Chromosome<T >);

public:
	pthread_mutex_t self_adapt_lock;
	pthread_cond_t self_adapt_wait;

	/**
	 * Create a manager for GA.
	 * @param population_size The size of population.
	 * @param chromosome_size The size of each chromosome.
	 * @param max_chromosome_value The maximum possible value for the chromosome.
	 * @param min_chromosome_value The minimum possible value for the chromosome.
	 * @param use_self_adaptive Whether to use a self adaptive approach. If this is true
	 * then the mutation rate will be updated based on the similarity of the population.
	 * @param mutation_rate The mutation rate that is used. This is the likelihood that the
	 * mutation operation is applied. If the self adaptive approach is used then this is
	 * the initial mutation rate.
	 * @param mutation_change_rate The rate by which the mutation rate will be updated.
	 * If use_self_adaptive is set to false then this parameter is ignored.
	 * @param similarity_index The threshold at which the similarity mutation rate is
	 * updated.
	 * @param crossover_rate The crossover rate, the likelihood that a chromosome
	 * has the crossover operation applied to it.
	 * @param clonning_rate The clonning rate, the likelihood that a cromosome will be
	 * cloned into the new population.
	 */
	Manager(unsigned int population_size, unsigned int chromosome_size, unsigned int max_generations_number,
			T max_chromosome_value, T min_chromosome_value, bool use_self_adaptive,
			double mutation_rate, double mutation_change_rate, double similarity_index,
			double crossover_rate) : population_size(population_size),
			chromosome_size(chromosome_size), max_generation_number(max_generation_number),
			max_chromosome_value(max_chromosome_value), min_chromosome_value(min_chromosome_value),
			use_self_adaptive(use_self_adaptive), mutation_rate(mutation_rate),
			mutation_change_rate(mutation_change_rate), similarity_index(similarity_index),
			crossover_rate(crossover_rate) {
		population = std::vector<Chromosome<T > >(population_size);
		initialize();
	}

	/**
	 * Create a non self-adaptive GA manager
	 * @param population_size The size of population.
	 * @param chromosome_size The size of each chromosome.
	 * @param max_chromosome_value The maximum possible value for the chromosome.
	 * @param min_chromosome_value The minimum possible value for the chromosome.
	 * @param mutation_rate The mutation rate that is used. This is the likelihood that the
	 * mutation operation is applied. If the self adaptive approach is used then this is
	 * the initial mutation rate.
	 * @param crossover_rate The crossover rate, the likelihood that a chromosome
	 * has the crossover operation applied to it.
	 * @param clonning_rate The clonning rate, the likelihood that a cromosome will be
	 * cloned into the new population.
	 */
	Manager(unsigned int population_size, unsigned int chromosome_size, unsigned int max_generation_number,
				T max_chromosome_value, T min_chromosome_value, double mutation_rate,
				double crossover_rate) : population_size(population_size),
				chromosome_size(chromosome_size), max_generation_number(max_generation_number),
				max_chromosome_value(max_chromosome_value), min_chromosome_value(min_chromosome_value),
				use_self_adaptive(false), mutation_rate(mutation_rate), mutation_change_rate(0),
				similarity_index(0), crossover_rate(crossover_rate), population(population_size) {

		initialize();

	}

	~Manager() {
		pthread_mutex_destroy(&self_adapt_lock);
		pthread_cond_destroy(&self_adapt_wait);
	}

        /**
	 * Run the algorithm for the specificed number of generations
	 */
	void run(double (*fitness_function)(Chromosome<T >)) {
		this->fitness_function = fitness_function;

		initPopulation();

		for(unsigned int i = 0; i < max_generation_number; i++) {
			runGeneration();
		}
	}

	/** TODO make this private (after testing)
	 * Prepare the population for the next generation by apply the genetic operations.
	 */
	void breed(std::vector<std::pair<unsigned int, double> > &fitness) {
		std::vector<Chromosome<T > > new_population;
		rw.init(fitness);

		// Iterate through the chromosomes
		while(new_population.size() < population_size) {
			// Use a random number between to identify which operation to apply (each operation gets a slice of the range)
			float selected_operation = op_dist(rand_engine);
			unsigned int selected_chromosome = rw.next();
			if(selected_operation <= crossover_rate) {
				// Crossover
				unsigned int other_selected_chromosome = rw.next();

				// TODO add a attribute to allow the user to decided whether to have redundent crossover
				// Since a crossover operation between the same chromosome is the same as clonning we should pick another one
				while(other_selected_chromosome == selected_chromosome) {
					other_selected_chromosome = rw.next();
				}

				population[selected_chromosome].crossover(population[other_selected_chromosome], new_population);

				//TODO fix, crossover can make so that the population contains 1 extra member (since it adds two)
				// What do we do to prevent this?
					// - Not allow crossover when we have size-1
					// - Allow crossover but reject one of the two results of the crossover
				// Mutate the second chromosome in the crossover
				mutate((*(new_population.end() - 2)));
			}
			else {
				// Clone
				population[selected_chromosome].clonning(new_population);
			}

			// Mutate the chromosome
			mutate(new_population.back());
		}

		// Update the population to the new population
		population = new_population; // Check if this creates a shallow copy (since we aren't going to change new_population so we just want it to be deallocated at the end of the method).

	}

	/**
 	 * Apply the self-adaptive operation to determine the similarity of the chromosomes
	 * and update the mutation rate accordingly.
	 *
	 * This might be best fit to have 1 thread designated for it (and if more are available use more).
	 * Since the fitness function is most likely the longest process, if we complete the fitness functions
	 * concurrently and then to the selfadaptive (which is a sort and then a comparison) nlogn + n. So by
	 * doing as many fitness function calls (available_threads - 2, 1 for self adaptive and 1 for fitness
	 * function manager) we can then call self adaptive as well and and therefore if the fitness functions
	 * take a long time to execute (or pop_size > available_threads - 2) then we will execute some fitness
	 * function but will actual finish the self adaptive. This means we wont be doing do all fitness functions
	 * then self adaptive (aka approx. fitness function execution time * pop_size/(available_threads - 1) + (self adaptive execution time)) rather we'll
	 * do (some) fitness functions and self adaptive and then remaining as threads become available (approx. fitness function execution * pop_size - 1 / (available_threads - 2) + .
	 */
	void selfAdapt() {
		// Determine how similar the chromosome is to the rest of the population

		// Sequencial solution
		// Iterate through the chromosomes
			// Calculate the current chromosome with each of the others in the population

		// Based on the similarity of the population identify adjust the mutaiton rate
			//if the similarity is too high (above threshold), increase mutation rate
			//if similarity is too low (below threshold), decrease mutation rate
			//otherwise (same as threshold), do nothing
	}

	/**
	 * TODO document
	 * @param param
	 */
	static void *applySelfAdaptive(void *param) {
		if(param != NULL) {
			Manager * m = (Manager *) param;
			while(true) {
				pthread_mutex_lock(&m->self_adapt_lock);
				pthread_cond_wait(&m->self_adapt_wait, &m->self_adapt_lock);
				pthread_mutex_unlock(&m->self_adapt_lock);

				m->selfAdapt();

				// proceed with calculating some fitness functions
			}

		}
		// TODO Deallocate m
		return NULL;
	}

	/**
	 * TODO document
	 * @param param
	 */
	static void *calcFitnessFunction(void *param) {
		if(param != NULL) {
			Manager * m = (Manager *) param;
			while(true) {
				unsigned int problem_index = m->safe_queue.waitToPop();

				// Can we trust the user to not change the chromosome? No.
				Chromosome<T > t = m->population[problem_index];
				std::pair<unsigned int, double >temp (problem_index, m->fitness_function(t));
				m->result_queue.push(temp);
			}

		}
		// TODO Deallocate m

		return NULL;
	}

	/**
	 * TODO make this private (after testing)
	 * Create an initial population of random chromosoms.
	 */
	void initPopulation() {
		Chromosome<unsigned int >::initPopulation(this->population, this->population_size, this->chromosome_size);
	}

	std::vector<Chromosome<T > > getPopulation() {
		return this->population;
	}

private:

	/**
	 * TODO document
	 */
	void initialize() {
		// Create the random objects that will be used
		std::random_device rd;
		rand_engine = std::mt19937 (rd());
		op_dist = std::uniform_real_distribution<float> (0.0, 1.0);
		mutation_dist = std::uniform_real_distribution<float> (0.0, 1.0);
		Chromosome<T >::initialize(chromosome_size, min_chromosome_value, max_chromosome_value);

		// Create the number of threads requested. If we are using self adaptive we will require 1 thread for the self adaptive
		for(unsigned int i = 0; i < number_of_threads - use_self_adaptive; i++) {
			pthread_t thread;
			threadpool.push_back(thread);
			pthread_create(&threadpool.back(), 0, calcFitnessFunction, (void *) this);

			// TODO decide if this is useful
			this->num_threads_used++;
		}

		if(use_self_adaptive) {
			pthread_mutex_init(&self_adapt_lock, 0);
			pthread_cond_init(&self_adapt_wait, 0);

			pthread_t self_adapt;
			pthread_create(&self_adapt, 0, applySelfAdaptive, (void *)this);
		}
	}

	/**
	 * TODO document
	 * @param chromosome
	 */
	void mutate(Chromosome<T > &chromosome) {
		if(mutation_dist(rand_engine) <= mutation_rate) {
			chromosome.mutate();
		}
	}

	/** TODO clean up this documentation
	 * Apply the fitness function to the population. Given the result of the
	 * fitness function, the next population is bread.
	 *
	 * There are several approaches we could take to mapping the number of available threads to the problems:
	 * 1. Use static division of work. That is to say, divide the work up as evenly as possible ahead of problem solving.
	 * eg. 1 thread is given pop_size / (available_threads - 1) chromosomes to solve the fitness function for.
	 * 	- Adv. less communication and no need for a management thread.
	 * 	- Adv. Easy to implement.
	 * 	- Dis. if more threads become available become available (most likely case, they finish their set of problems early)
	 * 	  then they will not be taken advantage of.
	 * 2. Use dynamic division of work. Assign the threads a work as the become available. This can happen in two ways;
	 * 2.1 Use static division and then load balance if new threads become available for work (while more work is pending).
	 * 	- Adv. basically the same as the static except take advantage of available resources
	 * 	- Dis. Re-balancing will take more communication.
	 * 	- Dis. Harder to implement (have to create a balancer which will transfer queued problems to the free thread.
	 * 	- Dis. Requires a managment thread.
	 * 2.2 Each thread is given a problem to solve and will pull off another problem once it is finished.
	 * 	- Adv. Can effectively balance the load
	 * 	- Adv. Easy to implement (with shared memory which threads have).
	 * 	- Dis. Requires more communication
	 * 	- Dis. Requires a manager thread
	 */
	void runGeneration() {

		// Given that threads are going to be used:
			// - Create a thread pool and attempt to assign a reduced set of chromosomes to each thread
			// - Since each chromosome is independent for the execution of the fitness function they can be 1 thread per chromosome (hypothedically)
		for(unsigned int i = 0; i < this->population_size; i++) {
			// Push on the index for each chromosome in the population.
			safe_queue.push(i);
		}
		// Could potentially have a second generic method that you could use to apply heuristics to a found solution.
			// eg; in N-Queens you can rotate the board in order to find more solutions.

		// Can be done concurrently with the fitness function
		if(use_self_adaptive) {
				// Create a thread to handle selfAdapt()
				pthread_mutex_lock(&self_adapt_lock);
				pthread_cond_signal(&self_adapt_wait);
				pthread_mutex_unlock(&self_adapt_lock);
		}

		// Main thread will wait for all children to finish executing before proceeding.
		// Construct the list of results for the fitness function in a map which maps the chromosome's index to the chromosome's fitness value.
		std::map<unsigned int, double > fitness_results;
		std::pair<unsigned int, double > result;

		// Wait for all the chromosomes to finish calculating their fitness value.
		while(fitness_results.size() < population_size) {
			result = result_queue.waitToPop();
			fitness_results[result.first] = result.second;
		}

		// TODO search for results

		breed(fitness_results);
	}
};

#endif /* MANAGER_HPP_ */
<commit_msg>FIXED: new_pop > pop_size bug<commit_after>
#ifndef MANAGER_HPP_
#define MANAGER_HPP_

#include <vector>			 // vector
#include <random>            // mt19937, uniform_int_distribution, random_device
#include <pthread.h>		 // pthreads
#include <utility>			 // make_pair

#include "Chromosome.hpp"
#include "RouletteWheel.hpp"
#include "SafeQueue.hpp"

template <class T>
class Manager {
protected:

	unsigned int population_size;
	unsigned int chromosome_size;

	unsigned int max_generation_number;

	T max_chromosome_value;
	T min_chromosome_value;

	bool use_self_adaptive;
	double mutation_rate;
	double mutation_change_rate;
	double similarity_index;

	// TODO check if clonning rate is by convention (1 - (mutation_rate + crossover)).
	//double clonning_rate;

	double crossover_rate;

	std::vector<Chromosome<T > > population;

	// Need to have some way of ensure no duplication of solutions
	std::vector<Chromosome<T > > solutions;

	RouletteWheel rw;
	//RouletteWheel op_roulettewheel;

	SafeQueue<unsigned int > safe_queue;
	SafeQueue<std::pair<unsigned int, double > > result_queue;

	std::vector<pthread_t > threadpool;

	std::mt19937 rand_engine;
	std::uniform_real_distribution<float> op_dist;
	std::uniform_real_distribution<float> mutation_dist;
	//std::uniform_int_distribution<int> chrom_dist;

	// With this we can limit the number of threads used
	unsigned int max_num_threads;
	unsigned int num_threads_used;

	// Library flags
	int number_of_nodes = 0;
	int number_of_threads = 5;

	// Fitness function
	double (*fitness_function)(Chromosome<T >);

public:
	pthread_mutex_t self_adapt_lock;
	pthread_cond_t self_adapt_wait;

	/**
	 * Create a manager for GA.
	 * @param population_size The size of population.
	 * @param chromosome_size The size of each chromosome.
	 * @param max_chromosome_value The maximum possible value for the chromosome.
	 * @param min_chromosome_value The minimum possible value for the chromosome.
	 * @param use_self_adaptive Whether to use a self adaptive approach. If this is true
	 * then the mutation rate will be updated based on the similarity of the population.
	 * @param mutation_rate The mutation rate that is used. This is the likelihood that the
	 * mutation operation is applied. If the self adaptive approach is used then this is
	 * the initial mutation rate.
	 * @param mutation_change_rate The rate by which the mutation rate will be updated.
	 * If use_self_adaptive is set to false then this parameter is ignored.
	 * @param similarity_index The threshold at which the similarity mutation rate is
	 * updated.
	 * @param crossover_rate The crossover rate, the likelihood that a chromosome
	 * has the crossover operation applied to it.
	 * @param clonning_rate The clonning rate, the likelihood that a cromosome will be
	 * cloned into the new population.
	 */
	Manager(unsigned int population_size, unsigned int chromosome_size, unsigned int max_generations_number,
			T max_chromosome_value, T min_chromosome_value, bool use_self_adaptive,
			double mutation_rate, double mutation_change_rate, double similarity_index,
			double crossover_rate) : population_size(population_size),
			chromosome_size(chromosome_size), max_generation_number(max_generation_number),
			max_chromosome_value(max_chromosome_value), min_chromosome_value(min_chromosome_value),
			use_self_adaptive(use_self_adaptive), mutation_rate(mutation_rate),
			mutation_change_rate(mutation_change_rate), similarity_index(similarity_index),
			crossover_rate(crossover_rate) {
		population = std::vector<Chromosome<T > >(population_size);
		initialize();
	}

	/**
	 * Create a non self-adaptive GA manager
	 * @param population_size The size of population.
	 * @param chromosome_size The size of each chromosome.
	 * @param max_chromosome_value The maximum possible value for the chromosome.
	 * @param min_chromosome_value The minimum possible value for the chromosome.
	 * @param mutation_rate The mutation rate that is used. This is the likelihood that the
	 * mutation operation is applied. If the self adaptive approach is used then this is
	 * the initial mutation rate.
	 * @param crossover_rate The crossover rate, the likelihood that a chromosome
	 * has the crossover operation applied to it.
	 * @param clonning_rate The clonning rate, the likelihood that a cromosome will be
	 * cloned into the new population.
	 */
	Manager(unsigned int population_size, unsigned int chromosome_size, unsigned int max_generation_number,
				T max_chromosome_value, T min_chromosome_value, double mutation_rate,
				double crossover_rate) : population_size(population_size),
				chromosome_size(chromosome_size), max_generation_number(max_generation_number),
				max_chromosome_value(max_chromosome_value), min_chromosome_value(min_chromosome_value),
				use_self_adaptive(false), mutation_rate(mutation_rate), mutation_change_rate(0),
				similarity_index(0), crossover_rate(crossover_rate), population(population_size) {

		initialize();

	}

	~Manager() {
		pthread_mutex_destroy(&self_adapt_lock);
		pthread_cond_destroy(&self_adapt_wait);
	}

        /**
	 * Run the algorithm for the specificed number of generations
	 */
	void run(double (*fitness_function)(Chromosome<T >)) {
		this->fitness_function = fitness_function;

		initPopulation();

		for(unsigned int i = 0; i < max_generation_number; i++) {
			runGeneration();
		}
	}

	/** TODO make this private (after testing)
	 * Prepare the population for the next generation by apply the genetic operations.
	 */
	void breed(std::vector<std::pair<unsigned int, double> > &fitness) {
		std::vector<Chromosome<T > > new_population;
		rw.init(fitness);

		// Iterate through the chromosomes
		while(new_population.size() < population_size) {
			// Use a random number between to identify which operation to apply (each operation gets a slice of the range)
			float selected_operation = op_dist(rand_engine);
			unsigned int selected_chromosome = rw.next();
			if(selected_operation <= crossover_rate) {
				// Crossover
				unsigned int other_selected_chromosome = rw.next();

				// TODO add a attribute to allow the user to decided whether to have redundent crossover
				// Since a crossover operation between the same chromosome is the same as clonning we should pick another one
				while(other_selected_chromosome == selected_chromosome) {
					other_selected_chromosome = rw.next();
				}

				population[selected_chromosome].crossover(population[other_selected_chromosome], new_population);

				// Mutate the second chromosome in the crossover
				mutate((*(new_population.end() - 2)));

				// Handle the case where the new_population.size() -1 == popluation size and then crossover is selected.
				if(new_population.size() == population_size+1) {
					new_population.pop_back();
				}
			}
			else {
				// Clone
				population[selected_chromosome].clonning(new_population);
			}

			// Mutate the chromosome
			mutate(new_population.back());
		}

		// Update the population to the new population
		population = new_population; // Check if this creates a shallow copy (since we aren't going to change new_population so we just want it to be deallocated at the end of the method).

	}

	/**
 	 * Apply the self-adaptive operation to determine the similarity of the chromosomes
	 * and update the mutation rate accordingly.
	 *
	 * This might be best fit to have 1 thread designated for it (and if more are available use more).
	 * Since the fitness function is most likely the longest process, if we complete the fitness functions
	 * concurrently and then to the selfadaptive (which is a sort and then a comparison) nlogn + n. So by
	 * doing as many fitness function calls (available_threads - 2, 1 for self adaptive and 1 for fitness
	 * function manager) we can then call self adaptive as well and and therefore if the fitness functions
	 * take a long time to execute (or pop_size > available_threads - 2) then we will execute some fitness
	 * function but will actual finish the self adaptive. This means we wont be doing do all fitness functions
	 * then self adaptive (aka approx. fitness function execution time * pop_size/(available_threads - 1) + (self adaptive execution time)) rather we'll
	 * do (some) fitness functions and self adaptive and then remaining as threads become available (approx. fitness function execution * pop_size - 1 / (available_threads - 2) + .
	 */
	void selfAdapt() {
		// Determine how similar the chromosome is to the rest of the population

		// Sequencial solution
		// Iterate through the chromosomes
			// Calculate the current chromosome with each of the others in the population

		// Based on the similarity of the population identify adjust the mutaiton rate
			//if the similarity is too high (above threshold), increase mutation rate
			//if similarity is too low (below threshold), decrease mutation rate
			//otherwise (same as threshold), do nothing
	}

	/**
	 * TODO document
	 * @param param
	 */
	static void *applySelfAdaptive(void *param) {
		if(param != NULL) {
			Manager * m = (Manager *) param;
			while(true) {
				pthread_mutex_lock(&m->self_adapt_lock);
				pthread_cond_wait(&m->self_adapt_wait, &m->self_adapt_lock);
				pthread_mutex_unlock(&m->self_adapt_lock);

				m->selfAdapt();

				// proceed with calculating some fitness functions
			}

		}
		// TODO Deallocate m
		return NULL;
	}

	/**
	 * TODO document
	 * @param param
	 */
	static void *calcFitnessFunction(void *param) {
		if(param != NULL) {
			Manager * m = (Manager *) param;
			while(true) {
				unsigned int problem_index = m->safe_queue.waitToPop();

				// Can we trust the user to not change the chromosome? No.
				Chromosome<T > t = m->population[problem_index];
				std::pair<unsigned int, double >temp (problem_index, m->fitness_function(t));
				m->result_queue.push(temp);
			}

		}
		// TODO Deallocate m

		return NULL;
	}

	/**
	 * TODO make this private (after testing)
	 * Create an initial population of random chromosoms.
	 */
	void initPopulation() {
		Chromosome<unsigned int >::initPopulation(this->population, this->population_size, this->chromosome_size);
	}

	std::vector<Chromosome<T > > getPopulation() {
		return this->population;
	}

private:

	/**
	 * TODO document
	 */
	void initialize() {
		// Create the random objects that will be used
		std::random_device rd;
		rand_engine = std::mt19937 (rd());
		op_dist = std::uniform_real_distribution<float> (0.0, 1.0);
		mutation_dist = std::uniform_real_distribution<float> (0.0, 1.0);
		Chromosome<T >::initialize(chromosome_size, min_chromosome_value, max_chromosome_value);

		// Create the number of threads requested. If we are using self adaptive we will require 1 thread for the self adaptive
		for(unsigned int i = 0; i < number_of_threads - use_self_adaptive; i++) {
			pthread_t thread;
			threadpool.push_back(thread);
			pthread_create(&threadpool.back(), 0, calcFitnessFunction, (void *) this);

			// TODO decide if this is useful
			this->num_threads_used++;
		}

		if(use_self_adaptive) {
			pthread_mutex_init(&self_adapt_lock, 0);
			pthread_cond_init(&self_adapt_wait, 0);

			pthread_t self_adapt;
			pthread_create(&self_adapt, 0, applySelfAdaptive, (void *)this);
		}
	}

	/**
	 * TODO document
	 * @param chromosome
	 */
	void mutate(Chromosome<T > &chromosome) {
		if(mutation_dist(rand_engine) <= mutation_rate) {
			chromosome.mutate();
		}
	}

	/** TODO clean up this documentation
	 * Apply the fitness function to the population. Given the result of the
	 * fitness function, the next population is bread.
	 *
	 * There are several approaches we could take to mapping the number of available threads to the problems:
	 * 1. Use static division of work. That is to say, divide the work up as evenly as possible ahead of problem solving.
	 * eg. 1 thread is given pop_size / (available_threads - 1) chromosomes to solve the fitness function for.
	 * 	- Adv. less communication and no need for a management thread.
	 * 	- Adv. Easy to implement.
	 * 	- Dis. if more threads become available become available (most likely case, they finish their set of problems early)
	 * 	  then they will not be taken advantage of.
	 * 2. Use dynamic division of work. Assign the threads a work as the become available. This can happen in two ways;
	 * 2.1 Use static division and then load balance if new threads become available for work (while more work is pending).
	 * 	- Adv. basically the same as the static except take advantage of available resources
	 * 	- Dis. Re-balancing will take more communication.
	 * 	- Dis. Harder to implement (have to create a balancer which will transfer queued problems to the free thread.
	 * 	- Dis. Requires a managment thread.
	 * 2.2 Each thread is given a problem to solve and will pull off another problem once it is finished.
	 * 	- Adv. Can effectively balance the load
	 * 	- Adv. Easy to implement (with shared memory which threads have).
	 * 	- Dis. Requires more communication
	 * 	- Dis. Requires a manager thread
	 */
	void runGeneration() {

		// Given that threads are going to be used:
			// - Create a thread pool and attempt to assign a reduced set of chromosomes to each thread
			// - Since each chromosome is independent for the execution of the fitness function they can be 1 thread per chromosome (hypothedically)
		for(unsigned int i = 0; i < this->population_size; i++) {
			// Push on the index for each chromosome in the population.
			safe_queue.push(i);
		}
		// Could potentially have a second generic method that you could use to apply heuristics to a found solution.
			// eg; in N-Queens you can rotate the board in order to find more solutions.

		// Can be done concurrently with the fitness function
		if(use_self_adaptive) {
				// Create a thread to handle selfAdapt()
				pthread_mutex_lock(&self_adapt_lock);
				pthread_cond_signal(&self_adapt_wait);
				pthread_mutex_unlock(&self_adapt_lock);
		}

		// Main thread will wait for all children to finish executing before proceeding.
		// Construct the list of results for the fitness function in a map which maps the chromosome's index to the chromosome's fitness value.
		std::map<unsigned int, double > fitness_results;
		std::pair<unsigned int, double > result;

		// Wait for all the chromosomes to finish calculating their fitness value.
		while(fitness_results.size() < population_size) {
			result = result_queue.waitToPop();
			fitness_results[result.first] = result.second;
		}

		// TODO search for results

		breed(fitness_results);
	}
};

#endif /* MANAGER_HPP_ */
<|endoftext|>


<commit_before>#include "rosplan_knowledge_base/KnowledgeComparitor.h"

#include <boost/algorithm/string.hpp>

/* implementation of KnowledgeComparitor.h */
namespace KCL_rosplan {

	/**
	 * returns true iff inequality is true
	 */
	bool KnowledgeComparitor::inequalityTrue(const rosplan_knowledge_msgs::KnowledgeItem &a, const std::vector<rosplan_knowledge_msgs::KnowledgeItem> &modelFunctions) {

		double lhs = KnowledgeComparitor::evaluateExpression(a.ineq.LHS, modelFunctions);
		double rhs = KnowledgeComparitor::evaluateExpression(a.ineq.RHS, modelFunctions);

		switch(a.ineq.comparison_type) {
			case rosplan_knowledge_msgs::DomainInequality::GREATER:   return lhs>rhs;
			case rosplan_knowledge_msgs::DomainInequality::GREATEREQ: return lhs>=rhs;
			case rosplan_knowledge_msgs::DomainInequality::LESS:      return lhs<rhs;
			case rosplan_knowledge_msgs::DomainInequality::LESSEQ:    return lhs<=rhs;
			case rosplan_knowledge_msgs::DomainInequality::EQUALS:    return lhs==rhs;
		}
		ROS_ERROR("KCL: (%s) Knowledge Comapritor does not recognise comparison type.", ros::this_node::getName().c_str());
		return false;
	}

	/**
	 * evaluates the prefix expression
	 */
	double KnowledgeComparitor::evaluateExpression(const rosplan_knowledge_msgs::ExprComposite &expr, const std::vector<rosplan_knowledge_msgs::KnowledgeItem> &modelFunctions) {

		std::vector<rosplan_knowledge_msgs::ExprBase> tokens = expr.tokens;

		bool pending_operand = false;
		std::vector<rosplan_knowledge_msgs::ExprBase> operator_stack;
		std::vector<rosplan_knowledge_msgs::ExprBase> operand_stack;
		for(int i=0;i<tokens.size();i++) {
			rosplan_knowledge_msgs::ExprBase token = tokens[i];
			switch(token.expr_type) {
				case rosplan_knowledge_msgs::ExprBase::OPERATOR:
					operator_stack.push_back(token);
					pending_operand = false;
					break;
				case rosplan_knowledge_msgs::ExprBase::CONSTANT:
				case rosplan_knowledge_msgs::ExprBase::FUNCTION:
				case rosplan_knowledge_msgs::ExprBase::SPECIAL:

					if(pending_operand) {
						while (operand_stack.size()>0) {
							rosplan_knowledge_msgs::ExprBase lhs = token;
							rosplan_knowledge_msgs::ExprBase rhs = operand_stack.back();
							operand_stack.pop_back();
							rosplan_knowledge_msgs::ExprBase op = operator_stack.back();
							operator_stack.back();
							double value = KnowledgeComparitor::evaluateOperation(
									KnowledgeComparitor::getValue(lhs, modelFunctions),
									KnowledgeComparitor::getValue(rhs, modelFunctions),
									op);
							token.expr_type = rosplan_knowledge_msgs::ExprBase::CONSTANT;
							token.constant = value;
						}
					}
					pending_operand = true;
					operand_stack.push_back(token);
					break;
			}
		}

		rosplan_knowledge_msgs::ExprBase result = operand_stack.back();
		operand_stack.pop_back();
		return getValue(result, modelFunctions);
	}

	/*
	 * evaluate numeric expression between two ExprBase messages.
	 */
	double KnowledgeComparitor::evaluateOperation(const double &lhs, const double &rhs, const rosplan_knowledge_msgs::ExprBase &op) {

		switch(op.op) {
			case rosplan_knowledge_msgs::ExprBase::ADD: return lhs+rhs;
			case rosplan_knowledge_msgs::ExprBase::SUB: return lhs-rhs;
			case rosplan_knowledge_msgs::ExprBase::MUL: return lhs*rhs;
			case rosplan_knowledge_msgs::ExprBase::DIV: return lhs/rhs;
			case rosplan_knowledge_msgs::ExprBase::UMINUS: return -lhs;
		}
		ROS_ERROR("KCL: (%s) Knowledge Comapritor does not recognise operator type.", ros::this_node::getName().c_str());
		return 0;
	}

	/*
	 * Find numeric value of an ExprBase message, i.e. evaluate the value of PDDL function
	 */
	double KnowledgeComparitor::getValue(const rosplan_knowledge_msgs::ExprBase &expr, const std::vector<rosplan_knowledge_msgs::KnowledgeItem> &modelFunctions) {
		switch(expr.expr_type) {
			case rosplan_knowledge_msgs::ExprBase::CONSTANT:
				return expr.constant;
			case rosplan_knowledge_msgs::ExprBase::FUNCTION:
				std::vector<rosplan_knowledge_msgs::KnowledgeItem>::const_iterator fit = modelFunctions.begin();
				for(; fit!=modelFunctions.end(); fit++) {
					if(expr.function.name == fit->attribute_name && expr.function.typed_parameters.size() == fit->values.size()) {
						// parameters
						bool match = true;
						for(size_t i=0;i<fit->values.size();i++) {
							if("" != expr.function.typed_parameters[i].value && !(boost::iequals(expr.function.typed_parameters[i].value, fit->values[i].value))) {
								match = false;
							}
						}
						if(match) {
							return fit->function_value;
						}
					}
				}
				return 0;
		}
		ROS_ERROR("KCL: (%s) Knowledge Comapritor cannot get value for base expression.", ros::this_node::getName().c_str());
		return 0;
	}

	/**
	 * returns true iff a matches the knowledge in b.
	 */
	bool KnowledgeComparitor::containsKnowledge(const rosplan_knowledge_msgs::KnowledgeItem &a, const rosplan_knowledge_msgs::KnowledgeItem &b) {

		int matches = 0;
		if(a.knowledge_type != b.knowledge_type) return false;

		switch(a.knowledge_type) {

		case rosplan_knowledge_msgs::KnowledgeItem::INSTANCE:
			{
				// check instance knowledge
				if(0!=a.instance_type.compare(b.instance_type)) return false;
				if(a.instance_name!="" && !boost::iequals(a.instance_name, b.instance_name)) return false;
				return true;
			}
			break;

		case rosplan_knowledge_msgs::KnowledgeItem::FUNCTION:

 			// compare functions (use _inequalityTrue_ to check function values)
			// Note: ContainsKnowledge checks if the two KnowledgeItems are the same. For functions, value is NOT
			//       checked as this may be used to compare. In order to compare the vlaue of the function the
            //       KnowledgeComparitor::inequalityTrue
			//if(a.function_value != b.function_value) return false;

		// check function or fact label and parameters all match
		case rosplan_knowledge_msgs::KnowledgeItem::FACT:
			{
				// label
				if(a.attribute_name=="") return true;
				if(!boost::iequals(a.attribute_name, b.attribute_name)) return false;

				// negative fact
				if(a.is_negative != b.is_negative) return false;

				// parameters
				if(a.values.size() != b.values.size()) return false;
				for(size_t i=0;i<a.values.size();i++) {
					if("" == a.values[i].value) {
						++matches;
					} else if(boost::iequals(a.values[i].value, b.values[i].value)) {
						++matches;
					}
				}
				return (matches == a.values.size());
			}
			break;
		}
	}

	/**
	 * returns true is the knowledge item contains the instance, as instance or attribute parameter.
	 */
	bool KnowledgeComparitor::containsInstance(const rosplan_knowledge_msgs::KnowledgeItem &a, std::string &name) {

		if(0==a.instance_name.compare(name))
			return true;

		for(size_t i=0;i<a.values.size();i++) {
			if(boost::iequals(a.values[i].value, name))
				return true;
		}

		return false;
	}

} // close namespace
<commit_msg>Update rosplan_knowledge_base/src/KnowledgeComparitor.cpp<commit_after>#include "rosplan_knowledge_base/KnowledgeComparitor.h"

#include <boost/algorithm/string.hpp>

/* implementation of KnowledgeComparitor.h */
namespace KCL_rosplan {

	/**
	 * returns true iff inequality is true
	 */
	bool KnowledgeComparitor::inequalityTrue(const rosplan_knowledge_msgs::KnowledgeItem &a, const std::vector<rosplan_knowledge_msgs::KnowledgeItem> &modelFunctions) {

		double lhs = KnowledgeComparitor::evaluateExpression(a.ineq.LHS, modelFunctions);
		double rhs = KnowledgeComparitor::evaluateExpression(a.ineq.RHS, modelFunctions);

		switch(a.ineq.comparison_type) {
			case rosplan_knowledge_msgs::DomainInequality::GREATER:   return lhs>rhs;
			case rosplan_knowledge_msgs::DomainInequality::GREATEREQ: return lhs>=rhs;
			case rosplan_knowledge_msgs::DomainInequality::LESS:      return lhs<rhs;
			case rosplan_knowledge_msgs::DomainInequality::LESSEQ:    return lhs<=rhs;
			case rosplan_knowledge_msgs::DomainInequality::EQUALS:    return lhs==rhs;
		}
		ROS_ERROR("KCL: (%s) Knowledge Comapritor does not recognise comparison type.", ros::this_node::getName().c_str());
		return false;
	}

	/**
	 * evaluates the prefix expression
	 */
	double KnowledgeComparitor::evaluateExpression(const rosplan_knowledge_msgs::ExprComposite &expr, const std::vector<rosplan_knowledge_msgs::KnowledgeItem> &modelFunctions) {

		std::vector<rosplan_knowledge_msgs::ExprBase> tokens = expr.tokens;

		bool pending_operand = false;
		std::vector<rosplan_knowledge_msgs::ExprBase> operator_stack;
		std::vector<rosplan_knowledge_msgs::ExprBase> operand_stack;
		for(int i=0;i<tokens.size();i++) {
			rosplan_knowledge_msgs::ExprBase token = tokens[i];
			switch(token.expr_type) {
				case rosplan_knowledge_msgs::ExprBase::OPERATOR:
					operator_stack.push_back(token);
					pending_operand = false;
					break;
				case rosplan_knowledge_msgs::ExprBase::CONSTANT:
				case rosplan_knowledge_msgs::ExprBase::FUNCTION:
				case rosplan_knowledge_msgs::ExprBase::SPECIAL:

					if(pending_operand) {
						while (operand_stack.size()>0) {
							rosplan_knowledge_msgs::ExprBase lhs = token;
							rosplan_knowledge_msgs::ExprBase rhs = operand_stack.back();
							operand_stack.pop_back();
							rosplan_knowledge_msgs::ExprBase op = operator_stack.back();
							operator_stack.back();
							double value = KnowledgeComparitor::evaluateOperation(
									KnowledgeComparitor::getValue(lhs, modelFunctions),
									KnowledgeComparitor::getValue(rhs, modelFunctions),
									op);
							token.expr_type = rosplan_knowledge_msgs::ExprBase::CONSTANT;
							token.constant = value;
						}
					}
					pending_operand = true;
					operand_stack.push_back(token);
					break;
			}
		}

		rosplan_knowledge_msgs::ExprBase result = operand_stack.back();
		operand_stack.pop_back();
		return getValue(result, modelFunctions);
	}

	/*
	 * evaluate numeric expression between two ExprBase messages.
	 */
	double KnowledgeComparitor::evaluateOperation(const double &lhs, const double &rhs, const rosplan_knowledge_msgs::ExprBase &op) {

		switch(op.op) {
			case rosplan_knowledge_msgs::ExprBase::ADD: return lhs+rhs;
			case rosplan_knowledge_msgs::ExprBase::SUB: return lhs-rhs;
			case rosplan_knowledge_msgs::ExprBase::MUL: return lhs*rhs;
			case rosplan_knowledge_msgs::ExprBase::DIV: return lhs/rhs;
			case rosplan_knowledge_msgs::ExprBase::UMINUS: return -lhs;
		}
		ROS_ERROR("KCL: (%s) Knowledge Comapritor does not recognise operator type.", ros::this_node::getName().c_str());
		return 0;
	}

	/*
	 * Find numeric value of an ExprBase message, i.e. evaluate the value of PDDL function
	 */
	double KnowledgeComparitor::getValue(const rosplan_knowledge_msgs::ExprBase &expr, const std::vector<rosplan_knowledge_msgs::KnowledgeItem> &modelFunctions) {
		switch(expr.expr_type) {
			case rosplan_knowledge_msgs::ExprBase::CONSTANT:
				return expr.constant;
			case rosplan_knowledge_msgs::ExprBase::FUNCTION:
				std::vector<rosplan_knowledge_msgs::KnowledgeItem>::const_iterator fit = modelFunctions.begin();
				for(; fit!=modelFunctions.end(); fit++) {
					if(expr.function.name == fit->attribute_name && expr.function.typed_parameters.size() == fit->values.size()) {
						// parameters
						bool match = true;
						for(size_t i=0;i<fit->values.size();i++) {
							if("" != expr.function.typed_parameters[i].value && !(boost::iequals(expr.function.typed_parameters[i].value, fit->values[i].value))) {
								match = false;
							}
						}
						if(match) {
							return fit->function_value;
						}
					}
				}
				return 0;
		}
		ROS_ERROR("KCL: (%s) Knowledge Comapritor cannot get value for base expression.", ros::this_node::getName().c_str());
		return 0;
	}

	/**
	 * returns true iff a matches the knowledge in b.
	 */
	bool KnowledgeComparitor::containsKnowledge(const rosplan_knowledge_msgs::KnowledgeItem &a, const rosplan_knowledge_msgs::KnowledgeItem &b) {

		int matches = 0;
		if(a.knowledge_type != b.knowledge_type) return false;

		switch(a.knowledge_type) {

		case rosplan_knowledge_msgs::KnowledgeItem::INSTANCE:
			{
				// check instance knowledge
				if(0!=a.instance_type.compare(b.instance_type)) return false;
				if(a.instance_name!="" && !boost::iequals(a.instance_name, b.instance_name)) return false;
				return true;
			}
			break;

		case rosplan_knowledge_msgs::KnowledgeItem::FUNCTION:

 			// compare functions (use _inequalityTrue_ to check function values)
			//       checked as this may be used to compare. In order to compare the vlaue of the function the
            //       KnowledgeComparitor::inequalityTrue
			//if(a.function_value != b.function_value) return false;

		// check function or fact label and parameters all match
		case rosplan_knowledge_msgs::KnowledgeItem::FACT:
			{
				// label
				if(a.attribute_name=="") return true;
				if(!boost::iequals(a.attribute_name, b.attribute_name)) return false;

				// negative fact
				if(a.is_negative != b.is_negative) return false;

				// parameters
				if(a.values.size() != b.values.size()) return false;
				for(size_t i=0;i<a.values.size();i++) {
					if("" == a.values[i].value) {
						++matches;
					} else if(boost::iequals(a.values[i].value, b.values[i].value)) {
						++matches;
					}
				}
				return (matches == a.values.size());
			}
			break;
		}
	}

	/**
	 * returns true is the knowledge item contains the instance, as instance or attribute parameter.
	 */
	bool KnowledgeComparitor::containsInstance(const rosplan_knowledge_msgs::KnowledgeItem &a, std::string &name) {

		if(0==a.instance_name.compare(name))
			return true;

		for(size_t i=0;i<a.values.size();i++) {
			if(boost::iequals(a.values[i].value, name))
				return true;
		}

		return false;
	}

} // close namespace
<|endoftext|>


<commit_before>/**************************************************************************
 *
 * Copyright 2011 Jose Fonseca
 * All Rights Reserved.
 *
 * 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 "glproc.hpp"
#include "os.hpp"
#include "os_string.hpp"

#if !defined(_WIN32)
#include <unistd.h> // for symlink
#include "dlopen.hpp"
#endif

/*
 * Handle to the true OpenGL library.
 */
#if defined(_WIN32)
HMODULE _libGlHandle = NULL;
#else
void *_libGlHandle = NULL;
#endif

#if defined(_WIN32)

void *
_getPublicProcAddress(const char *procName)
{
    if (!_libGlHandle) {
        char szDll[MAX_PATH] = {0};

        if (!GetSystemDirectoryA(szDll, MAX_PATH)) {
            return NULL;
        }

        strcat(szDll, "\\opengl32.dll");

        _libGlHandle = LoadLibraryA(szDll);
        if (!_libGlHandle) {
            os::log("apitrace: error: couldn't load %s\n", szDll);
            return NULL;
        }
    }

    return (void *)GetProcAddress(_libGlHandle, procName);
}

void *
_getPrivateProcAddress(const char *procName) {
    return (void *)_wglGetProcAddress(procName);
}

#elif defined(__APPLE__)

/*
 * Path to the true OpenGL framework
 */
static const char *libgl_filename = "/System/Library/Frameworks/OpenGL.framework/OpenGL";

/*
 * Lookup a libGL symbol
 */
void * _libgl_sym(const char *symbol)
{
    void *result;

    if (!_libGlHandle) {
        /*
         * Unfortunately we can't just dlopen the true dynamic library because
         * DYLD_LIBRARY_PATH/DYLD_FRAMEWORK_PATH take precedence, even for
         * absolute paths.  So we create a temporary symlink, and dlopen that
         * instead.
         */

        os::String temp_template = os::getTemporaryDirectoryPath();
        temp_template.append("tmp.XXXXXX");
        char *temp_filename = temp_template.buf(temp_template.length() + 1);

        if (mktemp(temp_filename) != NULL) {
            if (symlink(libgl_filename, temp_filename) == 0) {
                _libGlHandle = dlopen(temp_filename, RTLD_LOCAL | RTLD_NOW | RTLD_FIRST);
                remove(temp_filename);
            }
        }

        if (!_libGlHandle) {
            os::log("apitrace: error: couldn't load %s\n", libgl_filename);
            os::abort();
            return NULL;
        }
    }

    result = dlsym(_libGlHandle, symbol);

#if 0
    if (result && result == dlsym(RTLD_SELF, symbol)) {
        os::log("apitrace: error: symbol lookup recursion\n");
        os::abort();
        return NULL;
    }
#endif

    return result;
}

void *
_getPublicProcAddress(const char *procName)
{
    return _libgl_sym(procName);
}

void *
_getPrivateProcAddress(const char *procName)
{
    return _libgl_sym(procName);
}

#else

#ifndef RTLD_DEEPBIND
#define RTLD_DEEPBIND 0
#endif

static inline void
logSymbol(const char *name, void *ptr) {
    if (0) {
        if (ptr) {
            Dl_info info;
            if (ptr && dladdr(ptr, &info)) {
                os::log("apitrace: %s -> \"%s\"\n", name, info.dli_fname);
            }
        } else {
            os::log("apitrace: %s -> NULL\n", name);
        }
    }
}

/*
 * Lookup a libGL symbol
 */
void * _libgl_sym(const char *symbol)
{
    void *result;

    if (!_libGlHandle) {
        /*
         * The app doesn't directly link against libGL.so, nor does it directly
         * dlopen it.  So we have to load it ourselves.
         */

        const char * libgl_filename = getenv("TRACE_LIBGL");

        if (!libgl_filename) {
            /*
             * Try to use whatever libGL.so the library is linked against.
             */

            result = dlsym(RTLD_NEXT, symbol);
            if (result) {
                _libGlHandle = RTLD_NEXT;
                return result;
            }

            libgl_filename = "libGL.so.1";
        }

        /*
         * It would have been preferable to use RTLD_LOCAL to ensure that the
         * application can never access libGL.so symbols directly, but this
         * won't work, given libGL.so often loads a driver specific SO and
         * exposes symbols to it.
         */

        _libGlHandle = _dlopen(libgl_filename, RTLD_GLOBAL | RTLD_LAZY | RTLD_DEEPBIND);
        if (!_libGlHandle) {
            os::log("apitrace: error: couldn't find libGL.so\n");
            return NULL;
        }
    }

    result = dlsym(_libGlHandle, symbol);

    logSymbol(symbol, result);

    return result;
}

void *
_getPublicProcAddress(const char *procName)
{
    return _libgl_sym(procName);
}

void *
_getPrivateProcAddress(const char *procName)
{
    return (void *)_glXGetProcAddressARB((const GLubyte *)procName);
}

#endif

<commit_msg>cglretrace: Better error message when failing to load system's OpenGL framework.<commit_after>/**************************************************************************
 *
 * Copyright 2011 Jose Fonseca
 * All Rights Reserved.
 *
 * 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 "glproc.hpp"
#include "os.hpp"
#include "os_string.hpp"

#if !defined(_WIN32)
#include <unistd.h> // for symlink
#include "dlopen.hpp"
#endif

/*
 * Handle to the true OpenGL library.
 */
#if defined(_WIN32)
HMODULE _libGlHandle = NULL;
#else
void *_libGlHandle = NULL;
#endif

#if defined(_WIN32)

void *
_getPublicProcAddress(const char *procName)
{
    if (!_libGlHandle) {
        char szDll[MAX_PATH] = {0};

        if (!GetSystemDirectoryA(szDll, MAX_PATH)) {
            return NULL;
        }

        strcat(szDll, "\\opengl32.dll");

        _libGlHandle = LoadLibraryA(szDll);
        if (!_libGlHandle) {
            os::log("apitrace: error: couldn't load %s\n", szDll);
            return NULL;
        }
    }

    return (void *)GetProcAddress(_libGlHandle, procName);
}

void *
_getPrivateProcAddress(const char *procName) {
    return (void *)_wglGetProcAddress(procName);
}

#elif defined(__APPLE__)

#include <sys/stat.h>

/*
 * Path to the true OpenGL framework
 */
static const char *libgl_filename = "/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL";

/*
 * Lookup a libGL symbol
 */
void * _libgl_sym(const char *symbol)
{
    void *result;

    if (!_libGlHandle) {
        /*
         * Unfortunately we can't just dlopen the true dynamic library because
         * DYLD_LIBRARY_PATH/DYLD_FRAMEWORK_PATH take precedence, even for
         * absolute paths.
         *
         * We used to overcome this by creating a temporary symlink, and dlopen'ing
         * that instead.
         *
         * However on newer macOS versions the OpenGL framework and dynamic
         * libraries don't exist on the filesystem, but rather in the dyld
         * shared system cache, so this trick no longer works.
         */

        struct stat st;
        int err = stat(libgl_filename, &st);
        if (err != 0) {
            os::log("apitrace: error: %s does not exist;"
                    " see https://github.com/apitrace/apitrace/issues/826\n",
                    libgl_filename);
            os::abort();
        } else {
            os::String temp_template = os::getTemporaryDirectoryPath();
            temp_template.append("tmp.XXXXXX");
            char *temp_filename = temp_template.buf(temp_template.length() + 1);

            if (mktemp(temp_filename) == NULL) {
                os::log("apitrace: error: mktemp failed\n");
                os::abort();
            }

            if (symlink(libgl_filename, temp_filename) != 0) {
                os::log("apitrace: error: symlink failed\n");
                remove(temp_filename);
                os::abort();
            }

            _libGlHandle = dlopen(temp_filename, RTLD_LOCAL | RTLD_NOW | RTLD_FIRST);
            if (!_libGlHandle) {
                os::log("apitrace: error: couldn't load %s -> %s\n", temp_filename, libgl_filename);
                os::abort();
            }

            remove(temp_filename);
        }
    }

    result = dlsym(_libGlHandle, symbol);

    if (result && result == dlsym(RTLD_SELF, symbol)) {
        os::log("apitrace: error: symbol lookup recursion\n");
        os::abort();
        return NULL;
    }

    return result;
}

void *
_getPublicProcAddress(const char *procName)
{
    return _libgl_sym(procName);
}

void *
_getPrivateProcAddress(const char *procName)
{
    return _libgl_sym(procName);
}

#else

#ifndef RTLD_DEEPBIND
#define RTLD_DEEPBIND 0
#endif

static inline void
logSymbol(const char *name, void *ptr) {
    if (0) {
        if (ptr) {
            Dl_info info;
            if (ptr && dladdr(ptr, &info)) {
                os::log("apitrace: %s -> \"%s\"\n", name, info.dli_fname);
            }
        } else {
            os::log("apitrace: %s -> NULL\n", name);
        }
    }
}

/*
 * Lookup a libGL symbol
 */
void * _libgl_sym(const char *symbol)
{
    void *result;

    if (!_libGlHandle) {
        /*
         * The app doesn't directly link against libGL.so, nor does it directly
         * dlopen it.  So we have to load it ourselves.
         */

        const char * libgl_filename = getenv("TRACE_LIBGL");

        if (!libgl_filename) {
            /*
             * Try to use whatever libGL.so the library is linked against.
             */

            result = dlsym(RTLD_NEXT, symbol);
            if (result) {
                _libGlHandle = RTLD_NEXT;
                return result;
            }

            libgl_filename = "libGL.so.1";
        }

        /*
         * It would have been preferable to use RTLD_LOCAL to ensure that the
         * application can never access libGL.so symbols directly, but this
         * won't work, given libGL.so often loads a driver specific SO and
         * exposes symbols to it.
         */

        _libGlHandle = _dlopen(libgl_filename, RTLD_GLOBAL | RTLD_LAZY | RTLD_DEEPBIND);
        if (!_libGlHandle) {
            os::log("apitrace: error: couldn't find libGL.so\n");
            return NULL;
        }
    }

    result = dlsym(_libGlHandle, symbol);

    logSymbol(symbol, result);

    return result;
}

void *
_getPublicProcAddress(const char *procName)
{
    return _libgl_sym(procName);
}

void *
_getPrivateProcAddress(const char *procName)
{
    return (void *)_glXGetProcAddressARB((const GLubyte *)procName);
}

#endif

<|endoftext|>


<commit_before>#include "CSceneManager.h"

#include <algorithm>
#include <sstream>

#include "CShaderLoader.h"
#include "CMeshLoader.h"
#include "CTextureLoader.h"

#include "CDeferredShadingManager.h"

CLight const CScene::NullLight;

CScene::CScene()
	: BindProjMatrix(ProjMatrix), BindViewMatrix(ViewMatrix), BindLightCount(LightCount), UseCulling(true)
{
	ActiveCamera = & DefaultCamera;

	addUniform("uProjMatrix", ProjMatrix);
	addUniform("uViewMatrix", ViewMatrix);
	addUniform("uLightCount", LightCount);

	RootObject.setCullingEnabled(false);
}

void CScene::addUniform(std::string const & label, boost::shared_ptr<IUniform const> const uniform)
{
	Uniforms[label] = uniform;
}

void CScene::removeUniform(std::string const & label)
{
	std::map<std::string, boost::shared_ptr<IUniform const> >::iterator it = Uniforms.find(label);

	if (it != Uniforms.end())
		Uniforms.erase(it);
}

ICameraSceneObject * const CScene::getActiveCamera()
{
	return ActiveCamera;
}

ICameraSceneObject const * const CScene::getActiveCamera() const
{
	return ActiveCamera;
}

void CScene::setActiveCamera(ICameraSceneObject * const activeCamera)
{
	ActiveCamera = activeCamera;
}

bool const CScene::isCullingEnabled() const
{
	return UseCulling;
}

void CScene::setCullingEnabled(bool const culling)
{
	UseCulling = culling;
}

boost::shared_ptr<IAttribute const> const CScene::getAttribute(std::string const & label) const
{
	return boost::shared_ptr<IAttribute const>();
}

unsigned int const digitCount(int n)
{
	int count = 1;
	if (n < 0)
	{
		n *= -1;
		++ count;
	}

	while (n > 10)
	{
		++ count;
		n /= 10;
	}

	return count;
}

boost::shared_ptr<IUniform const> const CScene::getUniform(std::string const & label) const
{
	if (label.substr(0, 8) == "uLights[")
	{
		std::stringstream ss(label.substr(8));
		unsigned int index;
		ss >> index;
		std::string remaining = ss.str();
		remaining = remaining.substr(2 + digitCount(index));

		if (remaining == "Color")
		{
			if (index >= Lights.size())
				return BindUniform(NullLight.Color);
			else
				return BindUniform(Lights[index]->Color);
		}
		else if (remaining == "Position")
		{
			if (index >= Lights.size())
				return BindUniform(NullLight.Position);
			else
				return BindUniform(Lights[index]->Position);
		}
	}

	std::map<std::string, boost::shared_ptr<IUniform const> >::const_iterator it = Uniforms.find(label);

	if (it != Uniforms.end())
		return it->second;

	return boost::shared_ptr<IUniform const>();
}

void CScene::update()
{
	ActiveCamera->recalculateViewMatrix();
	ViewMatrix = ActiveCamera->getViewMatrix();
	ProjMatrix = ActiveCamera->getProjectionMatrix();

	if (LightCount != Lights.size())
	{
		SceneChanged = true;
		LightCount = Lights.size();
	}

	RootObject.updateAbsoluteTransformation();
	RootObject.update();
}

GLuint CSceneManager::QuadHandle = 0;

CSceneManager::CSceneManager(SPosition2 const & screenSize)
	: FinalBlurSize(0.0f), SceneFrameBuffer(0),
	EffectManager(0), ScreenSize(screenSize)
{
	CurrentScene = this;

	// Create a simple quad VBO to use for draw operations!
	if (! QuadHandle)
	{
		GLfloat QuadVertices[] =
		{
			-1.0, -1.0,
			1.0, -1.0,
			1.0,  1.0,
			-1.0,  1.0
		};

		glGenBuffers(1, & QuadHandle);
		glBindBuffer(GL_ARRAY_BUFFER, QuadHandle);
		glBufferData(GL_ARRAY_BUFFER, sizeof(QuadVertices), QuadVertices, GL_STATIC_DRAW);
	}

	STextureCreationFlags Flags;
	Flags.MipMaps = false;
	Flags.Wrap = GL_CLAMP_TO_EDGE;
	SceneFrameTexture = new CTexture(ScreenSize, true, Flags);
	SceneDepthBuffer = new CRenderBufferObject(GL_DEPTH_COMPONENT24, ScreenSize);

	SceneFrameBuffer = new CFrameBufferObject();
	SceneFrameBuffer->attach(SceneDepthBuffer, GL_DEPTH_ATTACHMENT);
	SceneFrameBuffer->attach(SceneFrameTexture, GL_COLOR_ATTACHMENT0);
	//SceneFrameBuffer->attach(SceneFrameTexture, GL_COLOR_ATTACHMENT1);

	if (! SceneFrameBuffer->isValid())
		std::cerr << "Failed to make FBO for scene drawing!!!!!!" << std::endl  << std::endl  << std::endl;

	EffectManager = DefaultManager = new CSceneEffectManager(this);
	EffectManager->setEffectEnabled(ESE_BLOOM, true);

	DeferredManager = new CDeferredShadingManager(this);

	BlurHorizontal = CShaderLoader::loadShader("FBO/QuadCopyUV.glsl", "BlurH.frag");
}

void CSceneManager::addSceneObject(ISceneObject * sceneObject)
{
	RootObject.addChild(sceneObject);
}

void CSceneManager::removeSceneObject(ISceneObject * sceneObject)
{
	RootObject.removeChild(sceneObject);
}

void CSceneManager::removeAllSceneObjects()
{
	RootObject.removeChildren();
}

bool sortISOXY (ISceneObject* a, ISceneObject* b) {
	SVector3f av = a->getAbsoluteBoundingBox().MinCorner;//getWorldBoundingBoxMinPoint();
	SVector3f bv = b->getAbsoluteBoundingBox().MaxCorner;//
	if(av.X == bv.X) {
		return av.Y < bv.Y;
	}
	else return av.X < bv.X;
}

void CSceneManager::drawAll()
{
	ISceneObject::resetObjectCounts();
	CurrentScene->update();

	if (EffectManager)
	{
		for (std::vector<CSceneEffectManager::SRenderPass>::iterator it = EffectManager->RenderPasses.begin(); it != EffectManager->RenderPasses.end(); ++ it)
		{
			if (it->Target)
				it->Target->bind();
			else
				glBindFramebuffer(GL_FRAMEBUFFER, 0);

			if (it->Pass == ERenderPass::DeferredLights)
			{
				glClearColor(0.f,0.f,0.f,0.f);
				glDisable(GL_DEPTH_TEST);
				glEnable(GL_BLEND);
				glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
			}

			if (it->Pass != ERenderPass::Default)
				glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

			load(it->Pass);
			RootObject.draw(CurrentScene, it->Pass, UseCulling);

			if (it->Pass != ERenderPass::DeferredLights) {
				glEnable(GL_ALPHA);
				glEnable(GL_BLEND);
				glEnable(GL_DEPTH_TEST);
				glDepthMask(GL_FALSE);
				glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			}
			else {
			}
			if (it->Pass != ERenderPass::DeferredLights) {
				glBlendFunc(GL_ONE, GL_MAX);
				glDepthMask(GL_TRUE);
				glDisable(GL_BLEND);
				glDisable(GL_ALPHA);
			}

			if (it->Pass == ERenderPass::DeferredLights)
			{
				glDisable(GL_BLEND);
				glEnable(GL_DEPTH_TEST);
			}
		}

		EffectManager->apply();
	}
	else
	{
		SceneFrameBuffer->bind();
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		glEnable(GL_ALPHA);
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE);
		RootObject.load(CurrentScene, ERenderPass::Default);
		RootObject.draw(CurrentScene, ERenderPass::Default, UseCulling);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE);
		glDisable(GL_BLEND);
		glDisable(GL_ALPHA);
	}

	SceneChanged = false;

	SceneFrameBuffer->bind();
	//printf("Num objects: %d\n", numObjects);
}

void CSceneManager::blurSceneIn(float seconds, float const RunTime)
{
	std::cout << "Blurring in scene..." << std::endl;
	BlurOutTime = 0;
	BlurInTime = seconds;
	CurTime = RunTime;
}

#include <CApplication.h>
void CSceneManager::endDraw()
{
	// Do fade-in
	if (CurTime == -1.0f)
		Dim = 1.0f;

	if (BlurInTime > 0.0f)
	{
		FinalBlurSize = 0.0f;
		Dim = std::max(1.0f - (BlurInTime - (CApplication::get().getRunTime() - CurTime))/BlurInTime, 0.0f);
		if ((CApplication::get().getRunTime() - CurTime) > BlurInTime)
		{
			BlurInTime = 0.0f;
			CurTime = -1.0f;
		}
	}

	// Draw to screen
	glBindFramebuffer(GL_FRAMEBUFFER, 0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glDisable(GL_DEPTH_TEST);

	// THE FINAL RENDER
	{
		CShaderContext Context(* BlurHorizontal);

		Context.bindTexture("uTexColor", SceneFrameTexture);
		Context.uniform("BlurSize", FinalBlurSize);
		Context.uniform("DimAmount", Dim);
		Context.bindBufferObject("aPosition", QuadHandle, 2);

		glDrawArrays(GL_QUADS, 0, 4);
	}

	glEnable(GL_DEPTH_TEST);
}

CMeshSceneObject * CSceneManager::addMeshSceneObject(CMesh * Mesh)
{
	CMeshSceneObject * Object = new CMeshSceneObject();
	Object->setMesh(Mesh);
	addSceneObject(Object);
	return Object;
}

CMeshSceneObject * CSceneManager::addMeshSceneObject(CMesh * Mesh, CShader * Shader, CShader * DeferredShader)
{
	CMeshSceneObject * Object = new CMeshSceneObject();
	Object->setMesh(Mesh);
	Object->setShader(ERenderPass::Default, Shader);
	Object->setShader(ERenderPass::DeferredColors, DeferredShader);
	addSceneObject(Object);
	return Object;
}

CMeshSceneObject * CSceneManager::addMeshSceneObject(CMesh * Mesh, CShader * Shader, CShader * DeferredShader, CRenderable::SMaterial const & Material)
{
	CMeshSceneObject * Object = new CMeshSceneObject();
	Object->setMesh(Mesh);
	Object->setShader(ERenderPass::Default, Shader);
	Object->setShader(ERenderPass::DeferredColors, DeferredShader);
	Object->setMaterial(Material);
	addSceneObject(Object);
	return Object;
}

CMeshSceneObject * CSceneManager::addMeshSceneObject(std::string const & Mesh, std::string const & Shader, std::string const & DeferredShader, CRenderable::SMaterial const & Material)
{
	CMeshSceneObject * Object = new CMeshSceneObject();
	Object->setMesh(CMeshLoader::load3dsMesh(Mesh));
	Object->setShader(ERenderPass::Default, CShaderLoader::loadShader(Shader));
	Object->setShader(ERenderPass::DeferredColors, CShaderLoader::loadShader(DeferredShader));
	Object->setMaterial(Material);
	addSceneObject(Object);
	return Object;
}

void CScene::enableDebugData(EDebugData::Domain const type)
{
	RootObject.enableDebugData(type);
}

void CScene::disableDebugData(EDebugData::Domain const type)
{
	RootObject.disableDebugData(type);
}

void CSceneManager::load()
{
	RootObject.load(this, ERenderPass::Default);
}

void CSceneManager::load(ERenderPass const Pass)
{
	RootObject.load(this, Pass);
}

CFrameBufferObject * CSceneManager::getSceneFrameBuffer()
{
	return SceneFrameBuffer;
}

CTexture * CSceneManager::getSceneFrameTexture()
{
	return SceneFrameTexture;
}

CRenderBufferObject * CSceneManager::getSceneDepthBuffer()
{
	return SceneDepthBuffer;
}

CSceneEffectManager * CSceneManager::getEffectManager()
{
	return EffectManager;
}

void CSceneManager::setEffectManager(CSceneEffectManager * effectManager)
{
	EffectManager = effectManager;
}

GLuint const CSceneManager::getQuadHandle()
{
	return QuadHandle;
}

SSize2 const & CSceneManager::getScreenSize() const
{
	return ScreenSize;
}

void CSceneManager::setDeferred(bool const isDeferred)
{
	EffectManager->setEffectEnabled(ESE_ALL, false);
	if (isDeferred)
		EffectManager = DeferredManager;
	else
		EffectManager = DefaultManager;
}
<commit_msg>+ Fixed non-clear (leftover from AlloyRender)<commit_after>#include "CSceneManager.h"

#include <algorithm>
#include <sstream>

#include "CShaderLoader.h"
#include "CMeshLoader.h"
#include "CTextureLoader.h"

#include "CDeferredShadingManager.h"

CLight const CScene::NullLight;

CScene::CScene()
	: BindProjMatrix(ProjMatrix), BindViewMatrix(ViewMatrix), BindLightCount(LightCount), UseCulling(true)
{
	ActiveCamera = & DefaultCamera;

	addUniform("uProjMatrix", ProjMatrix);
	addUniform("uViewMatrix", ViewMatrix);
	addUniform("uLightCount", LightCount);

	RootObject.setCullingEnabled(false);
}

void CScene::addUniform(std::string const & label, boost::shared_ptr<IUniform const> const uniform)
{
	Uniforms[label] = uniform;
}

void CScene::removeUniform(std::string const & label)
{
	std::map<std::string, boost::shared_ptr<IUniform const> >::iterator it = Uniforms.find(label);

	if (it != Uniforms.end())
		Uniforms.erase(it);
}

ICameraSceneObject * const CScene::getActiveCamera()
{
	return ActiveCamera;
}

ICameraSceneObject const * const CScene::getActiveCamera() const
{
	return ActiveCamera;
}

void CScene::setActiveCamera(ICameraSceneObject * const activeCamera)
{
	ActiveCamera = activeCamera;
}

bool const CScene::isCullingEnabled() const
{
	return UseCulling;
}

void CScene::setCullingEnabled(bool const culling)
{
	UseCulling = culling;
}

boost::shared_ptr<IAttribute const> const CScene::getAttribute(std::string const & label) const
{
	return boost::shared_ptr<IAttribute const>();
}

unsigned int const digitCount(int n)
{
	int count = 1;
	if (n < 0)
	{
		n *= -1;
		++ count;
	}

	while (n > 10)
	{
		++ count;
		n /= 10;
	}

	return count;
}

boost::shared_ptr<IUniform const> const CScene::getUniform(std::string const & label) const
{
	if (label.substr(0, 8) == "uLights[")
	{
		std::stringstream ss(label.substr(8));
		unsigned int index;
		ss >> index;
		std::string remaining = ss.str();
		remaining = remaining.substr(2 + digitCount(index));

		if (remaining == "Color")
		{
			if (index >= Lights.size())
				return BindUniform(NullLight.Color);
			else
				return BindUniform(Lights[index]->Color);
		}
		else if (remaining == "Position")
		{
			if (index >= Lights.size())
				return BindUniform(NullLight.Position);
			else
				return BindUniform(Lights[index]->Position);
		}
	}

	std::map<std::string, boost::shared_ptr<IUniform const> >::const_iterator it = Uniforms.find(label);

	if (it != Uniforms.end())
		return it->second;

	return boost::shared_ptr<IUniform const>();
}

void CScene::update()
{
	ActiveCamera->recalculateViewMatrix();
	ViewMatrix = ActiveCamera->getViewMatrix();
	ProjMatrix = ActiveCamera->getProjectionMatrix();

	if (LightCount != Lights.size())
	{
		SceneChanged = true;
		LightCount = Lights.size();
	}

	RootObject.updateAbsoluteTransformation();
	RootObject.update();
}

GLuint CSceneManager::QuadHandle = 0;

CSceneManager::CSceneManager(SPosition2 const & screenSize)
	: FinalBlurSize(0.0f), SceneFrameBuffer(0),
	EffectManager(0), ScreenSize(screenSize)
{
	CurrentScene = this;

	// Create a simple quad VBO to use for draw operations!
	if (! QuadHandle)
	{
		GLfloat QuadVertices[] =
		{
			-1.0, -1.0,
			1.0, -1.0,
			1.0,  1.0,
			-1.0,  1.0
		};

		glGenBuffers(1, & QuadHandle);
		glBindBuffer(GL_ARRAY_BUFFER, QuadHandle);
		glBufferData(GL_ARRAY_BUFFER, sizeof(QuadVertices), QuadVertices, GL_STATIC_DRAW);
	}

	STextureCreationFlags Flags;
	Flags.MipMaps = false;
	Flags.Wrap = GL_CLAMP_TO_EDGE;
	SceneFrameTexture = new CTexture(ScreenSize, true, Flags);
	SceneDepthBuffer = new CRenderBufferObject(GL_DEPTH_COMPONENT24, ScreenSize);

	SceneFrameBuffer = new CFrameBufferObject();
	SceneFrameBuffer->attach(SceneDepthBuffer, GL_DEPTH_ATTACHMENT);
	SceneFrameBuffer->attach(SceneFrameTexture, GL_COLOR_ATTACHMENT0);
	//SceneFrameBuffer->attach(SceneFrameTexture, GL_COLOR_ATTACHMENT1);

	if (! SceneFrameBuffer->isValid())
		std::cerr << "Failed to make FBO for scene drawing!!!!!!" << std::endl  << std::endl  << std::endl;

	EffectManager = DefaultManager = new CSceneEffectManager(this);
	EffectManager->setEffectEnabled(ESE_BLOOM, true);

	DeferredManager = new CDeferredShadingManager(this);

	BlurHorizontal = CShaderLoader::loadShader("FBO/QuadCopyUV.glsl", "BlurH.frag");
}

void CSceneManager::addSceneObject(ISceneObject * sceneObject)
{
	RootObject.addChild(sceneObject);
}

void CSceneManager::removeSceneObject(ISceneObject * sceneObject)
{
	RootObject.removeChild(sceneObject);
}

void CSceneManager::removeAllSceneObjects()
{
	RootObject.removeChildren();
}

bool sortISOXY (ISceneObject* a, ISceneObject* b) {
	SVector3f av = a->getAbsoluteBoundingBox().MinCorner;//getWorldBoundingBoxMinPoint();
	SVector3f bv = b->getAbsoluteBoundingBox().MaxCorner;//
	if(av.X == bv.X) {
		return av.Y < bv.Y;
	}
	else return av.X < bv.X;
}

void CSceneManager::drawAll()
{
	ISceneObject::resetObjectCounts();
	CurrentScene->update();

	if (EffectManager)
	{
		for (std::vector<CSceneEffectManager::SRenderPass>::iterator it = EffectManager->RenderPasses.begin(); it != EffectManager->RenderPasses.end(); ++ it)
		{
			if (it->Target)
				it->Target->bind();
			else
				glBindFramebuffer(GL_FRAMEBUFFER, 0);

			if (it->Pass == ERenderPass::DeferredLights)
			{
				glClearColor(0.f,0.f,0.f,0.f);
				glDisable(GL_DEPTH_TEST);
				glEnable(GL_BLEND);
				glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
			}

			//if (it->Pass != ERenderPass::Default)
				glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

			load(it->Pass);
			RootObject.draw(CurrentScene, it->Pass, UseCulling);

			if (it->Pass != ERenderPass::DeferredLights) {
				glEnable(GL_ALPHA);
				glEnable(GL_BLEND);
				glEnable(GL_DEPTH_TEST);
				glDepthMask(GL_FALSE);
				glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
			}
			else {
			}
			if (it->Pass != ERenderPass::DeferredLights) {
				glBlendFunc(GL_ONE, GL_MAX);
				glDepthMask(GL_TRUE);
				glDisable(GL_BLEND);
				glDisable(GL_ALPHA);
			}

			if (it->Pass == ERenderPass::DeferredLights)
			{
				glDisable(GL_BLEND);
				glEnable(GL_DEPTH_TEST);
			}
		}

		EffectManager->apply();
	}
	else
	{
		SceneFrameBuffer->bind();
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		glEnable(GL_ALPHA);
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE);
		RootObject.load(CurrentScene, ERenderPass::Default);
		RootObject.draw(CurrentScene, ERenderPass::Default, UseCulling);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE);
		glDisable(GL_BLEND);
		glDisable(GL_ALPHA);
	}

	SceneChanged = false;

	SceneFrameBuffer->bind();
	//printf("Num objects: %d\n", numObjects);
}

void CSceneManager::blurSceneIn(float seconds, float const RunTime)
{
	std::cout << "Blurring in scene..." << std::endl;
	BlurOutTime = 0;
	BlurInTime = seconds;
	CurTime = RunTime;
}

#include <CApplication.h>
void CSceneManager::endDraw()
{
	// Do fade-in
	if (CurTime == -1.0f)
		Dim = 1.0f;

	if (BlurInTime > 0.0f)
	{
		FinalBlurSize = 0.0f;
		Dim = std::max(1.0f - (BlurInTime - (CApplication::get().getRunTime() - CurTime))/BlurInTime, 0.0f);
		if ((CApplication::get().getRunTime() - CurTime) > BlurInTime)
		{
			BlurInTime = 0.0f;
			CurTime = -1.0f;
		}
	}

	// Draw to screen
	glBindFramebuffer(GL_FRAMEBUFFER, 0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glDisable(GL_DEPTH_TEST);

	// THE FINAL RENDER
	{
		CShaderContext Context(* BlurHorizontal);

		Context.bindTexture("uTexColor", SceneFrameTexture);
		Context.uniform("BlurSize", FinalBlurSize);
		Context.uniform("DimAmount", Dim);
		Context.bindBufferObject("aPosition", QuadHandle, 2);

		glDrawArrays(GL_QUADS, 0, 4);
	}

	glEnable(GL_DEPTH_TEST);
}

CMeshSceneObject * CSceneManager::addMeshSceneObject(CMesh * Mesh)
{
	CMeshSceneObject * Object = new CMeshSceneObject();
	Object->setMesh(Mesh);
	addSceneObject(Object);
	return Object;
}

CMeshSceneObject * CSceneManager::addMeshSceneObject(CMesh * Mesh, CShader * Shader, CShader * DeferredShader)
{
	CMeshSceneObject * Object = new CMeshSceneObject();
	Object->setMesh(Mesh);
	Object->setShader(ERenderPass::Default, Shader);
	Object->setShader(ERenderPass::DeferredColors, DeferredShader);
	addSceneObject(Object);
	return Object;
}

CMeshSceneObject * CSceneManager::addMeshSceneObject(CMesh * Mesh, CShader * Shader, CShader * DeferredShader, CRenderable::SMaterial const & Material)
{
	CMeshSceneObject * Object = new CMeshSceneObject();
	Object->setMesh(Mesh);
	Object->setShader(ERenderPass::Default, Shader);
	Object->setShader(ERenderPass::DeferredColors, DeferredShader);
	Object->setMaterial(Material);
	addSceneObject(Object);
	return Object;
}

CMeshSceneObject * CSceneManager::addMeshSceneObject(std::string const & Mesh, std::string const & Shader, std::string const & DeferredShader, CRenderable::SMaterial const & Material)
{
	CMeshSceneObject * Object = new CMeshSceneObject();
	Object->setMesh(CMeshLoader::load3dsMesh(Mesh));
	Object->setShader(ERenderPass::Default, CShaderLoader::loadShader(Shader));
	Object->setShader(ERenderPass::DeferredColors, CShaderLoader::loadShader(DeferredShader));
	Object->setMaterial(Material);
	addSceneObject(Object);
	return Object;
}

void CScene::enableDebugData(EDebugData::Domain const type)
{
	RootObject.enableDebugData(type);
}

void CScene::disableDebugData(EDebugData::Domain const type)
{
	RootObject.disableDebugData(type);
}

void CSceneManager::load()
{
	RootObject.load(this, ERenderPass::Default);
}

void CSceneManager::load(ERenderPass const Pass)
{
	RootObject.load(this, Pass);
}

CFrameBufferObject * CSceneManager::getSceneFrameBuffer()
{
	return SceneFrameBuffer;
}

CTexture * CSceneManager::getSceneFrameTexture()
{
	return SceneFrameTexture;
}

CRenderBufferObject * CSceneManager::getSceneDepthBuffer()
{
	return SceneDepthBuffer;
}

CSceneEffectManager * CSceneManager::getEffectManager()
{
	return EffectManager;
}

void CSceneManager::setEffectManager(CSceneEffectManager * effectManager)
{
	EffectManager = effectManager;
}

GLuint const CSceneManager::getQuadHandle()
{
	return QuadHandle;
}

SSize2 const & CSceneManager::getScreenSize() const
{
	return ScreenSize;
}

void CSceneManager::setDeferred(bool const isDeferred)
{
	EffectManager->setEffectEnabled(ESE_ALL, false);
	if (isDeferred)
		EffectManager = DeferredManager;
	else
		EffectManager = DefaultManager;
}
<|endoftext|>