<commit_before>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include <SpikeHwIndication.h>
#include <SpikeHwRequest.h>
#include "dmaManager.h"
#include "spikehw.h"
#include <iostream>
#include <functional>
#ifdef REGISTER_SPIKE_DEVICES
#include <riscv/sim.h>
#include <riscv/devices.h>
#endif

int verbose = 0;

class SpikeHwIndication : public SpikeHwIndicationWrapper
{
    sem_t sem;
public:
    int irq;
    uint32_t buf[16];
    IrqCallback irqCallback;

  void irqChanged( const uint8_t irq, const uint16_t intrSources ) {
    if (intrSources & (1 << 5)) fprintf(stderr, "iic intr=%d %04x\n", irq, intrSources);
      if (verbose) fprintf(stderr, "SpikeHw::irqChanged %d intr sources %x\n", irq, intrSources);
      this->irq = irq;
      if (irqCallback)
	irqCallback(irq);
    }
    virtual void resetDone() {
	fprintf(stderr, "reset done\n");
	sem_post(&sem);
    }
    virtual void status ( const uint8_t mmcm_locked, const uint8_t irq, const uint16_t intrSources ) {
	fprintf(stderr, "axi eth status mmcm_locked=%d irq=%d intr sources=%x\n", mmcm_locked, irq, intrSources);
	sem_post(&sem);
    }

    void wait() {
	struct timespec timeout;
	timeout.tv_sec = 1000;
	timeout.tv_nsec = 0;
	if (0) {
	  for (int tries = 0; tries < 10; tries++) {
	    int status = sem_timedwait(&sem, &timeout);
	    if (status != 0 && errno == ETIMEDOUT) {
	      if (tries > 5)
		fprintf(stderr, "%s:%d: try %d timed out waiting for response status=%d errno=%d\n", __FILE__, __LINE__, tries, status, errno);
	    } else {
	      break;
	    }
	  }
	} else {
	  sem_wait(&sem);
	}
    }

    void readDone ( const uint32_t value ) {
	buf[0] = value;
	if (verbose) fprintf(stderr, "readDone value=%08x\n", value);
	sem_post(&sem);
    }

    void writeDone (  ) {
	if (verbose) fprintf(stderr, "writeDone\n");
	sem_post(&sem);
    }

    void readFlashDone ( const uint32_t value ) {
	buf[0] = value;
	if (verbose) fprintf(stderr, "readFlashDone value=%08x\n", value);
	sem_post(&sem);
    }

    void writeFlashDone (  ) {
	if (verbose) fprintf(stderr, "writeFlashDone\n");
	sem_post(&sem);
    }

    SpikeHwIndication(unsigned int id, IrqCallback callback=0) : SpikeHwIndicationWrapper(id), irq(0), irqCallback(callback) {
      sem_init(&sem, 0, 0);
    }
};

SpikeHwRequestProxy *request;
SpikeHwIndication *indication;

SpikeHw::SpikeHw(IrqCallback callback)
    : request(0), indication(0), dmaManager(0), didReset(false)
{
    request = new SpikeHwRequestProxy(IfcNames_SpikeHwRequestS2H);
    indication = new SpikeHwIndication(IfcNames_SpikeHwIndicationH2S, callback);
    dmaManager = platformInit();
    request->setFlashParameters(100);
}

SpikeHw::~SpikeHw()
{
  //delete request;
  //delete indication;
  request = 0;
  indication = 0;
}

void SpikeHw::maybeReset()
{
    if (0)
    if (!didReset) {
	fprintf(stderr, "resetting flash\n");
	request->reset();
	indication->wait();
	//request->setParameters(50, 0);
	fprintf(stderr, "done resetting flash\n");
	didReset = true;
    }
}

void SpikeHw::status()
{
    request->status();
    indication->wait();
}

void SpikeHw::setupDma(uint32_t memfd)
{
    int memref = dmaManager->reference(memfd);
    fprintf(stderr, "SpikeHw::setupDma memfd=%d memref=%d\n", memfd, memref);
    request->setupDma(memref);
}

void SpikeHw::read(unsigned long offset, uint8_t *buf)
{
    maybeReset();

    if (verbose) fprintf(stderr, "SpikeHw::read offset=%lx\n", offset);
    request->read(offset);
    indication->wait();
    if (verbose) fprintf(stderr, "SpikeHw::read offset=%lx value=%x\n", offset, *(uint32_t *)indication->buf);
    memcpy(buf, indication->buf, 4);
}

void SpikeHw::write(unsigned long offset, const uint8_t *buf)
{
    maybeReset();

    if (verbose) fprintf(stderr, "SpikeHw::write offset=%lx value=%x\n", offset, *(uint32_t *)buf);
    request->write(offset, *(uint32_t *)buf);
    indication->wait();
    //request->status();
    //indication->wait();
}

uint32_t SpikeHw::read(unsigned long offset)
{
    maybeReset();

    //if (verbose || (offset > 0x101000)) fprintf(stderr, "SpikeHw::read offset=%08lx\n", offset);
    request->read(offset);
    indication->wait();
    //if (verbose || (offset > 0x101000)) fprintf(stderr, "SpikeHw::read done value=%x\n", *(uint32_t *)indication->buf);
    return *(uint32_t *)indication->buf;
}

void SpikeHw::write(unsigned long offset, const uint32_t value)
{
    maybeReset();

    //if (verbose || (offset > 0x101000)) fprintf(stderr, "SpikeHw::write offset=%08lx value=%x\n", offset, value);
    request->write(offset, value);
    indication->wait();
    //if (verbose || (offset > 0x101000)) fprintf(stderr, "SpikeHw::write done\n");
}

void SpikeHw::setFlashParameters(unsigned long cycles)
{
    request->setFlashParameters(cycles);
}

void SpikeHw::readFlash(unsigned long offset, uint8_t *buf)
{
    maybeReset();

    if (verbose) fprintf(stderr, "SpikeHw::readFlash offset=%lx\n", offset);
    request->readFlash(offset);
    indication->wait();
    if (verbose) fprintf(stderr, "SpikeHw::readFlash offset=%lx value=%x\n", offset, *(uint32_t *)indication->buf);
    memcpy(buf, indication->buf, 4);
}

void SpikeHw::writeFlash(unsigned long offset, const uint8_t *buf)
{
    maybeReset();

    if (verbose) fprintf(stderr, "SpikeHw::writeFlash offset=%lx value=%x\n", offset, *(uint32_t *)buf);
    request->writeFlash(offset, *(uint32_t *)buf);
    indication->wait();
}

bool SpikeHw::hasInterrupt()
{
    return indication->irq;
}
void SpikeHw::clearInterrupt()
{
    indication->irq = 0;
}

SpikeHw *spikeHw;

#ifdef REGISTER_SPIKE_DEVICES
class spikehw_device_t : public abstract_device_t {
public:
  spikehw_device_t();
  bool has_interrupt();
  bool load(reg_t addr, size_t len, uint8_t* bytes);
  bool store(reg_t addr, size_t len, const uint8_t* bytes);
  static abstract_device_t *make_device();
};

spikehw_device_t::spikehw_device_t()
{
  if (!spikeHw)
    spikeHw = new SpikeHw();
}

bool spikehw_device_t::has_interrupt()
{
    if (spikeHw->hasInterrupt()) {
	spikeHw->clearInterrupt();
	return true;
    }
    return false;
}

bool spikehw_device_t::load(reg_t addr, size_t len, uint8_t* bytes)
{
    spikeHw->read(addr, bytes); // always reads 4 bytes
    return true;
}

bool spikehw_device_t::store(reg_t addr, size_t len, const uint8_t* bytes)
{
    spikeHw->write(addr, bytes);
    return true;
}

abstract_device_t *spikehw_device_t::make_device()
{
    std::cerr << "make_device called" << std::endl;
    return new spikehw_device_t();
}

class spikeflash_device_t : public abstract_device_t {
public:
  spikeflash_device_t();
  bool load(reg_t addr, size_t len, uint8_t* bytes);
  bool store(reg_t addr, size_t len, const uint8_t* bytes);
  static abstract_device_t *make_device();
};

spikeflash_device_t::spikeflash_device_t()
{
  if (!spikeHw)
    spikeHw = new SpikeHw();
}

bool spikeflash_device_t::load(reg_t addr, size_t len, uint8_t* bytes)
{
    if (addr & 1 && len != 1) fprintf(stderr, "spikeflash::load addr=%08lx len=%ld\n", addr, len);
    if (addr & 1) {
	uint8_t data[2];
	spikeHw->readFlash(addr, data); // always reads 4 bytes
	bytes[0] = data[1];
	if (len > 1)
	    return false;
	else
	    return true;
    }

    while (len) {
	spikeHw->readFlash(addr, bytes); // always reads 4 bytes
	if (len < 2)
	    break;
	addr  += 2;
	bytes += 2;
	len   -= 2;
    }
    return true;
}

bool spikeflash_device_t::store(reg_t addr, size_t len, const uint8_t* bytes)
{
    //fprintf(stderr, "spikeflash::store addr=%08lx len=%ld bytes=%02x\n", addr, len, *(uint16_t *)bytes);
    if (len != 2)
      return false;
    spikeHw->writeFlash(addr, bytes);
    return true;
}

abstract_device_t *spikeflash_device_t::make_device()
{
    std::cerr << "spikeflash_device_t::make_device called" << std::endl;
    return new spikeflash_device_t();
}

class devicetree_device_t : public abstract_device_t {
public:
    devicetree_device_t();
    bool load(reg_t addr, size_t len, uint8_t* bytes);
    bool store(reg_t addr, size_t len, const uint8_t* bytes);
    static abstract_device_t *make_device();
private:
    const char *dtb;
    size_t dtbsz;
};

devicetree_device_t::devicetree_device_t()
{
    int fd = open("devicetree.dtb", O_RDONLY);
    if (fd > 0) {
	struct stat statbuf;
	int status = fstat(fd, &statbuf);
	fprintf(stderr, "fstat status %d size %ld\n", status, statbuf.st_size);
	if (status == 0) {
	    dtb = (const char *)mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
	    dtbsz = statbuf.st_size;
	    fprintf(stderr, "mapped dtb at %p (%ld bytes)\n", dtb, dtbsz);
	}
	close(fd);
    } else {
	fprintf(stderr, "Could not open devicetree.dtb\n");
    }
}

bool devicetree_device_t::load(reg_t addr, size_t len, uint8_t* bytes)
{
    if (dtb && dtb != MAP_FAILED) {
	if ((addr < dtbsz) && (bytes != 0)) {
	    memcpy(bytes, dtb + addr, len);
	    return true;
	}
    }
    return false;
}

bool devicetree_device_t::store(reg_t addr, size_t len, const uint8_t* bytes)
{
    return true;
}

abstract_device_t *devicetree_device_t::make_device()
{
    std::cerr << "devicetree_device_t::make_device called" << std::endl;
    return new devicetree_device_t();
}

char *SpikeHw::allocate_mem(size_t memsz)
{
    if (!spikeHw)
	spikeHw = new SpikeHw();
    int memfd = portalAlloc(memsz, 1);
    if (memfd < 0)
	return 0;
    char *buf = (char *)portalMmap(memfd, memsz);
    if (buf == MAP_FAILED) {
	close(memfd);
	return 0;
    }
    fprintf(stderr, "SpikeHw::allocate_mem memsz=%lx memfd=%d buf=%p\n", memsz, memfd, buf);
    spikeHw->setupDma(memfd);
    return buf;
}

REGISTER_MEM_ALLOCATOR(SpikeHw::allocate_mem);
REGISTER_DEVICE(devicetree, 0x04080000, devicetree_device_t::make_device);
REGISTER_DEVICE(spikehw,    0x04100000, spikehw_device_t::make_device);
REGISTER_DEVICE(spikeflash, 0x08000000, spikeflash_device_t::make_device);
#endif

#ifndef REGISTER_SPIKE_DEVICES
extern "C" {

    struct FpgaOps {
	uint64_t (*read)(uint64_t addr);
	void (*write)(uint64_t addr, uint64_t value);
	void (*close)();
    };

    uint64_t fpga_read(uint64_t addr)
    {
      uint64_t val = spikeHw->read(0x100000 + addr);
      //      if (addr == 0x1018)
      //	fprintf(stderr, "next interrupt %lx\n", val);
      return val;
    }

    void fpga_write(uint64_t addr, uint64_t value)
    {
	spikeHw->write(0x100000 + addr, value);
    }

    void fpga_close()
    {
    }

    void *fpgadev_init(void (*irqCallback)(int irq)) {
	fprintf(stderr, "connectal.so init called\n");
	if (!spikeHw)
	    spikeHw = new SpikeHw(irqCallback);
	struct FpgaOps *ops = (struct FpgaOps *)malloc(sizeof(struct FpgaOps));
	ops->read = fpga_read;
	ops->write = fpga_write;
	ops->close = fpga_close;
	return ops;
    }
}
#endif
<commit_msg>deassert i2c reset<commit_after>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include <SpikeHwIndication.h>
#include <SpikeHwRequest.h>
#include "dmaManager.h"
#include "spikehw.h"
#include <iostream>
#include <functional>
#ifdef REGISTER_SPIKE_DEVICES
#include <riscv/sim.h>
#include <riscv/devices.h>
#endif

int verbose = 0;

class SpikeHwIndication : public SpikeHwIndicationWrapper
{
    sem_t sem;
public:
    int irq;
    uint32_t buf[16];
    IrqCallback irqCallback;

  void irqChanged( const uint8_t irq, const uint16_t intrSources ) {
    if (intrSources & (1 << 5)) fprintf(stderr, "iic intr=%d %04x\n", irq, intrSources);
      if (verbose) fprintf(stderr, "SpikeHw::irqChanged %d intr sources %x\n", irq, intrSources);
      this->irq = irq;
      if (irqCallback)
	irqCallback(irq);
    }
    virtual void resetDone() {
	fprintf(stderr, "reset done\n");
	sem_post(&sem);
    }
    virtual void status ( const uint8_t mmcm_locked, const uint8_t irq, const uint16_t intrSources ) {
	fprintf(stderr, "axi eth status mmcm_locked=%d irq=%d intr sources=%x\n", mmcm_locked, irq, intrSources);
	sem_post(&sem);
    }

    void wait() {
	struct timespec timeout;
	timeout.tv_sec = 1000;
	timeout.tv_nsec = 0;
	if (0) {
	  for (int tries = 0; tries < 10; tries++) {
	    int status = sem_timedwait(&sem, &timeout);
	    if (status != 0 && errno == ETIMEDOUT) {
	      if (tries > 5)
		fprintf(stderr, "%s:%d: try %d timed out waiting for response status=%d errno=%d\n", __FILE__, __LINE__, tries, status, errno);
	    } else {
	      break;
	    }
	  }
	} else {
	  sem_wait(&sem);
	}
    }

    void readDone ( const uint32_t value ) {
	buf[0] = value;
	if (verbose) fprintf(stderr, "readDone value=%08x\n", value);
	sem_post(&sem);
    }

    void writeDone (  ) {
	if (verbose) fprintf(stderr, "writeDone\n");
	sem_post(&sem);
    }

    void readFlashDone ( const uint32_t value ) {
	buf[0] = value;
	if (verbose) fprintf(stderr, "readFlashDone value=%08x\n", value);
	sem_post(&sem);
    }

    void writeFlashDone (  ) {
	if (verbose) fprintf(stderr, "writeFlashDone\n");
	sem_post(&sem);
    }

    SpikeHwIndication(unsigned int id, IrqCallback callback=0) : SpikeHwIndicationWrapper(id), irq(0), irqCallback(callback) {
      sem_init(&sem, 0, 0);
    }
};

SpikeHwRequestProxy *request;
SpikeHwIndication *indication;

SpikeHw::SpikeHw(IrqCallback callback)
    : request(0), indication(0), dmaManager(0), didReset(false)
{
    request = new SpikeHwRequestProxy(IfcNames_SpikeHwRequestS2H);
    indication = new SpikeHwIndication(IfcNames_SpikeHwIndicationH2S, callback);
    dmaManager = platformInit();
    request->setFlashParameters(100);
    request->iicReset(0); // de-assert reset
}

SpikeHw::~SpikeHw()
{
  //delete request;
  //delete indication;
  request = 0;
  indication = 0;
}

void SpikeHw::maybeReset()
{
    if (0)
    if (!didReset) {
	fprintf(stderr, "resetting flash\n");
	request->reset();
	indication->wait();
	//request->setParameters(50, 0);
	fprintf(stderr, "done resetting flash\n");
	didReset = true;
    }
}

void SpikeHw::status()
{
    request->status();
    indication->wait();
}

void SpikeHw::setupDma(uint32_t memfd)
{
    int memref = dmaManager->reference(memfd);
    fprintf(stderr, "SpikeHw::setupDma memfd=%d memref=%d\n", memfd, memref);
    request->setupDma(memref);
}

void SpikeHw::read(unsigned long offset, uint8_t *buf)
{
    maybeReset();

    if (verbose) fprintf(stderr, "SpikeHw::read offset=%lx\n", offset);
    request->read(offset);
    indication->wait();
    if (verbose) fprintf(stderr, "SpikeHw::read offset=%lx value=%x\n", offset, *(uint32_t *)indication->buf);
    memcpy(buf, indication->buf, 4);
}

void SpikeHw::write(unsigned long offset, const uint8_t *buf)
{
    maybeReset();

    if (verbose) fprintf(stderr, "SpikeHw::write offset=%lx value=%x\n", offset, *(uint32_t *)buf);
    request->write(offset, *(uint32_t *)buf);
    indication->wait();
    //request->status();
    //indication->wait();
}

uint32_t SpikeHw::read(unsigned long offset)
{
    maybeReset();

    //if (verbose || (offset > 0x101000)) fprintf(stderr, "SpikeHw::read offset=%08lx\n", offset);
    request->read(offset);
    indication->wait();
    //if (verbose || (offset > 0x101000)) fprintf(stderr, "SpikeHw::read done value=%x\n", *(uint32_t *)indication->buf);
    return *(uint32_t *)indication->buf;
}

void SpikeHw::write(unsigned long offset, const uint32_t value)
{
    maybeReset();

    //if (verbose || (offset > 0x101000)) fprintf(stderr, "SpikeHw::write offset=%08lx value=%x\n", offset, value);
    request->write(offset, value);
    indication->wait();
    //if (verbose || (offset > 0x101000)) fprintf(stderr, "SpikeHw::write done\n");
}

void SpikeHw::setFlashParameters(unsigned long cycles)
{
    request->setFlashParameters(cycles);
}

void SpikeHw::readFlash(unsigned long offset, uint8_t *buf)
{
    maybeReset();

    if (verbose) fprintf(stderr, "SpikeHw::readFlash offset=%lx\n", offset);
    request->readFlash(offset);
    indication->wait();
    if (verbose) fprintf(stderr, "SpikeHw::readFlash offset=%lx value=%x\n", offset, *(uint32_t *)indication->buf);
    memcpy(buf, indication->buf, 4);
}

void SpikeHw::writeFlash(unsigned long offset, const uint8_t *buf)
{
    maybeReset();

    if (verbose) fprintf(stderr, "SpikeHw::writeFlash offset=%lx value=%x\n", offset, *(uint32_t *)buf);
    request->writeFlash(offset, *(uint32_t *)buf);
    indication->wait();
}

bool SpikeHw::hasInterrupt()
{
    return indication->irq;
}
void SpikeHw::clearInterrupt()
{
    indication->irq = 0;
}

SpikeHw *spikeHw;

#ifdef REGISTER_SPIKE_DEVICES
class spikehw_device_t : public abstract_device_t {
public:
  spikehw_device_t();
  bool has_interrupt();
  bool load(reg_t addr, size_t len, uint8_t* bytes);
  bool store(reg_t addr, size_t len, const uint8_t* bytes);
  static abstract_device_t *make_device();
};

spikehw_device_t::spikehw_device_t()
{
  if (!spikeHw)
    spikeHw = new SpikeHw();
}

bool spikehw_device_t::has_interrupt()
{
    if (spikeHw->hasInterrupt()) {
	spikeHw->clearInterrupt();
	return true;
    }
    return false;
}

bool spikehw_device_t::load(reg_t addr, size_t len, uint8_t* bytes)
{
    spikeHw->read(addr, bytes); // always reads 4 bytes
    return true;
}

bool spikehw_device_t::store(reg_t addr, size_t len, const uint8_t* bytes)
{
    spikeHw->write(addr, bytes);
    return true;
}

abstract_device_t *spikehw_device_t::make_device()
{
    std::cerr << "make_device called" << std::endl;
    return new spikehw_device_t();
}

class spikeflash_device_t : public abstract_device_t {
public:
  spikeflash_device_t();
  bool load(reg_t addr, size_t len, uint8_t* bytes);
  bool store(reg_t addr, size_t len, const uint8_t* bytes);
  static abstract_device_t *make_device();
};

spikeflash_device_t::spikeflash_device_t()
{
  if (!spikeHw)
    spikeHw = new SpikeHw();
}

bool spikeflash_device_t::load(reg_t addr, size_t len, uint8_t* bytes)
{
    if (addr & 1 && len != 1) fprintf(stderr, "spikeflash::load addr=%08lx len=%ld\n", addr, len);
    if (addr & 1) {
	uint8_t data[2];
	spikeHw->readFlash(addr, data); // always reads 4 bytes
	bytes[0] = data[1];
	if (len > 1)
	    return false;
	else
	    return true;
    }

    while (len) {
	spikeHw->readFlash(addr, bytes); // always reads 4 bytes
	if (len < 2)
	    break;
	addr  += 2;
	bytes += 2;
	len   -= 2;
    }
    return true;
}

bool spikeflash_device_t::store(reg_t addr, size_t len, const uint8_t* bytes)
{
    //fprintf(stderr, "spikeflash::store addr=%08lx len=%ld bytes=%02x\n", addr, len, *(uint16_t *)bytes);
    if (len != 2)
      return false;
    spikeHw->writeFlash(addr, bytes);
    return true;
}

abstract_device_t *spikeflash_device_t::make_device()
{
    std::cerr << "spikeflash_device_t::make_device called" << std::endl;
    return new spikeflash_device_t();
}

class devicetree_device_t : public abstract_device_t {
public:
    devicetree_device_t();
    bool load(reg_t addr, size_t len, uint8_t* bytes);
    bool store(reg_t addr, size_t len, const uint8_t* bytes);
    static abstract_device_t *make_device();
private:
    const char *dtb;
    size_t dtbsz;
};

devicetree_device_t::devicetree_device_t()
{
    int fd = open("devicetree.dtb", O_RDONLY);
    if (fd > 0) {
	struct stat statbuf;
	int status = fstat(fd, &statbuf);
	fprintf(stderr, "fstat status %d size %ld\n", status, statbuf.st_size);
	if (status == 0) {
	    dtb = (const char *)mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
	    dtbsz = statbuf.st_size;
	    fprintf(stderr, "mapped dtb at %p (%ld bytes)\n", dtb, dtbsz);
	}
	close(fd);
    } else {
	fprintf(stderr, "Could not open devicetree.dtb\n");
    }
}

bool devicetree_device_t::load(reg_t addr, size_t len, uint8_t* bytes)
{
    if (dtb && dtb != MAP_FAILED) {
	if ((addr < dtbsz) && (bytes != 0)) {
	    memcpy(bytes, dtb + addr, len);
	    return true;
	}
    }
    return false;
}

bool devicetree_device_t::store(reg_t addr, size_t len, const uint8_t* bytes)
{
    return true;
}

abstract_device_t *devicetree_device_t::make_device()
{
    std::cerr << "devicetree_device_t::make_device called" << std::endl;
    return new devicetree_device_t();
}

char *SpikeHw::allocate_mem(size_t memsz)
{
    if (!spikeHw)
	spikeHw = new SpikeHw();
    int memfd = portalAlloc(memsz, 1);
    if (memfd < 0)
	return 0;
    char *buf = (char *)portalMmap(memfd, memsz);
    if (buf == MAP_FAILED) {
	close(memfd);
	return 0;
    }
    fprintf(stderr, "SpikeHw::allocate_mem memsz=%lx memfd=%d buf=%p\n", memsz, memfd, buf);
    spikeHw->setupDma(memfd);
    return buf;
}

REGISTER_MEM_ALLOCATOR(SpikeHw::allocate_mem);
REGISTER_DEVICE(devicetree, 0x04080000, devicetree_device_t::make_device);
REGISTER_DEVICE(spikehw,    0x04100000, spikehw_device_t::make_device);
REGISTER_DEVICE(spikeflash, 0x08000000, spikeflash_device_t::make_device);
#endif

#ifndef REGISTER_SPIKE_DEVICES
extern "C" {

    struct FpgaOps {
	uint64_t (*read)(uint64_t addr);
	void (*write)(uint64_t addr, uint64_t value);
	void (*close)();
    };

    uint64_t fpga_read(uint64_t addr)
    {
      uint64_t val = spikeHw->read(0x100000 + addr);
      return val;
    }

    void fpga_write(uint64_t addr, uint64_t value)
    {
	spikeHw->write(0x100000 + addr, value);
    }

    void fpga_close()
    {
    }

    void *fpgadev_init(void (*irqCallback)(int irq)) {
	fprintf(stderr, "connectal.so init called\n");
	if (!spikeHw)
	    spikeHw = new SpikeHw(irqCallback);
	struct FpgaOps *ops = (struct FpgaOps *)malloc(sizeof(struct FpgaOps));
	ops->read = fpga_read;
	ops->write = fpga_write;
	ops->close = fpga_close;
	return ops;
    }
}
#endif
<|endoftext|>


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

#include <fulanghua_ekf_2d/pose_estimator.h>

#include <boost/assign.hpp>

#include <Eigen/LU>
#include <Eigen/Dense>

namespace fulanghua {

double normalize_rad(double th) {
    while(th > M_PI) th -= 2 * M_PI;
    while(th < -M_PI) th += 2 * M_PI;

    return th;
}

PoseEstimator::PoseEstimator(ros::NodeHandle &node) :
    enable_gpos_meas_(true),
    update_rate_(100),
    output_frame_("combined_odom"),
    base_frame_("map"),
    x_est_(Eigen::Vector4d::Zero()),
    cov_est_(Eigen::Matrix4d::Identity()),
    pose_pub_(node.advertise<geometry_msgs::PoseWithCovarianceStamped>("self_pose", 10))
{
    ros::NodeHandle nh_private("~");

    nh_private.param("output_frame", output_frame_, output_frame_);
    nh_private.param("base_frame", base_frame_, base_frame_);

    double motion_x_err, motion_y_err, motion_ang_err, motion_vel_err;
    double observation_x_err, observation_y_err, observation_ang_err, observation_vel_err;

    nh_private.param("motion_x_err", motion_x_err, 0.1);
    nh_private.param("motion_y_err", motion_y_err, 0.1);
    nh_private.param("motion_ang_err", motion_ang_err, 0.1);
    nh_private.param("motion_vel_err", motion_vel_err, 0.05);

    nh_private.param("observation_x_err", observation_x_err, 1.5);
    nh_private.param("observation_y_err", observation_y_err, 1.5);
    nh_private.param("observation_ang_err", observation_ang_err, 0.1);
    nh_private.param("observation_vel_err", observation_vel_err, 0.05);

    motion_cov_ << motion_x_err * motion_x_err, 0.0, 0.0, 0.0,
                   0.0, motion_y_err * motion_y_err, 0.0, 0.0,
                   0.0, 0.0, motion_ang_err * motion_ang_err, 0.0,
                   0.0, 0.0, 0.0, motion_vel_err * motion_vel_err;

    observation_cov_ << observation_x_err * observation_x_err, 0.0, 0.0, 0.0,
                       0.0, observation_y_err * observation_y_err, 0.0, 0.0,
                       0.0, 0.0, observation_ang_err * observation_ang_err, 0.0,
                       0.0, 0.0, 0.0, observation_vel_err * observation_vel_err;

    nh_private.param("enable_gpos_meas", enable_gpos_meas_, enable_gpos_meas_);

    imu_sub_ = node.subscribe("imu", 10, &PoseEstimator::imu_callback, this);
    odom_sub_ = node.subscribe("odom", 10, &PoseEstimator::odom_callback, this);

    if(enable_gpos_meas_)
        gpos_meas_sub_ = node.subscribe("meas_gpos", 10, &PoseEstimator::gpos_meas_callback, this);

}

void PoseEstimator::spin() {
    ros::Rate rate(update_rate_);
    ros::Time old_filter_stamp(0);
    bool meas_initialized = false;

    while(ros::ok()) {
        ros::spinOnce();
        rate.sleep();

        if(old_filter_stamp != ros::Time(0) && imu_stamp_ != ros::Time(0) && odom_stamp_ != ros::Time(0)) {
            if(enable_gpos_meas_) {
                if(gpos_meas_stamp_ != ros::Time(0)) meas_initialized = true;
            } else {
                meas_initialized = true;
            }
        }

        if(meas_initialized) {

            ros::Time now = ros::Time::now();
            ros::Time filter_stamp = now;

            filter_stamp = std::min(filter_stamp, odom_stamp_);
            filter_stamp = std::min(filter_stamp, imu_stamp_);

            if(enable_gpos_meas_)
                filter_stamp = std::min(filter_stamp, gpos_meas_stamp_);

            double dt = (now - old_filter_stamp).toSec();
            if(fabs(dt) < 0.0001) continue;

            if((ros::Time::now() - filter_stamp).toSec() > 1.0) {
                ROS_WARN("receive data are too old!");
                continue;
            }

            Eigen::Vector2d est_pos;
            double est_yaw;
            Eigen::Matrix3d est_cov;
            if(!estimate(est_pos, est_yaw, est_cov, filter_stamp, dt)) continue;

            geometry_msgs::PoseWithCovarianceStamped est_pose;
            est_pose.header.stamp = filter_stamp;
            est_pose.header.frame_id = base_frame_;
            est_pose.pose.pose.position.x = est_pos.x();
            est_pose.pose.pose.position.y = est_pos.y();
            est_pose.pose.pose.orientation = tf::createQuaternionMsgFromYaw(est_yaw);

            est_pose.pose.covariance = boost::assign::list_of
                (est_cov(0)) (0) (0) (0) (0) (0)
                (0) (est_cov(1)) (0) (0) (0) (0)
                (0) (0) (999999.9) (0) (0) (0)
                (0) (0) (0) (999999.9) (0) (0)
                (0) (0) (0) (0) (0) (est_cov(2));

            pose_pub_.publish(est_pose);

            geometry_msgs::TransformStamped tran;
            tran.header.stamp = filter_stamp;
            tran.header.frame_id = base_frame_;
            tran.child_frame_id = output_frame_;
            tran.transform.translation.x = est_pose.pose.pose.position.x;
            tran.transform.translation.y = est_pose.pose.pose.position.y;
            tran.transform.translation.z = 0.0;
            tran.transform.rotation = est_pose.pose.pose.orientation;

            tf_broadcaster_.sendTransform(tran);

            old_filter_stamp = now;
        } else {
            old_filter_stamp = ros::Time::now();

            if(transformer_.canTransform(base_frame_, "odom", old_filter_stamp)) {
                transformer_.lookupTransform("odom", base_frame_, old_filter_stamp, old_odom_meas_);
            }
        }
    }
}

bool PoseEstimator::estimate(Eigen::Vector2d &pos, double &yaw, Eigen::Matrix3d &cov_xy_th, const ros::Time &filter_stamp, double dt) {

    tf::StampedTransform odom_meas;
    if(!transformer_.canTransform(base_frame_, "odom", filter_stamp)) {
        ROS_WARN("Failed transform of odom data");
        return false;
    } else {
        transformer_.lookupTransform("odom", base_frame_, filter_stamp, odom_meas);
    }

    double gpos_meas_x, gpos_meas_y;
    if(enable_gpos_meas_) {
        tf::StampedTransform gpos_meas;
        if(!transformer_.canTransform(base_frame_, "gpos_meas", filter_stamp)) {
            ROS_WARN("Failed transform of gpos_meas data");
            return false;
        } else {
            transformer_.lookupTransform("gpos_meas", base_frame_, filter_stamp, gpos_meas);
        }

        gpos_meas_x = gpos_meas.getOrigin().x();
        gpos_meas_y = gpos_meas.getOrigin().y();
    } else {
        gpos_meas_x = odom_meas.getOrigin().x();
        gpos_meas_y = odom_meas.getOrigin().y();
    }

    tf::StampedTransform imu_meas;
    if(!transformer_.canTransform(base_frame_, "imu", filter_stamp)) {
        ROS_WARN("Failed transform of imu data");
        return false;
    } else {
        transformer_.lookupTransform("imu", base_frame_, filter_stamp, imu_meas);
    }

    double odom_linear_x = (odom_meas.getOrigin().x() - old_odom_meas_.getOrigin().x()) / dt;

    double odom_angular_z;
    double tmp_r, tmp_p, odom_yaw;
    odom_meas.getBasis().getEulerYPR(odom_yaw, tmp_p, tmp_r);
    double tmp_old_r, tmp_old_p, old_odom_yaw;
    old_odom_meas_.getBasis().getEulerYPR(old_odom_yaw, tmp_old_p, tmp_old_r);
    odom_angular_z = (odom_yaw - old_odom_yaw) / dt;

    ///< @todo use tf_listener for imu frame
    Eigen::Vector3d imu_rpy;
    //imu_meas.getBasis().getEulerYPR(imu_rpy.z(), imu_rpy.y(). imu_rpy.x());

    //predict
    Eigen::Vector2d u(odom_linear_x, odom_angular_z);
    Eigen::Vector4d x_pred = motion_model(x_est_, u, dt);
    Eigen::Matrix4d JF = jacob_motion_model(x_pred, u, dt);
    Eigen::Matrix4d cov_pred = JF * cov_est_ * JF.transpose() + motion_cov_;

    //update
    Eigen::Vector4d x(gpos_meas_x, gpos_meas_y, imu_rpy.y(), odom_linear_x);
    Eigen::Vector4d z = observation_model(x);
    Eigen::Matrix4d H = jacob_observation_model(x_pred);
    Eigen::Vector4d y = z - observation_model(x_pred);
    y(2) = normalize_rad(y(2));
    Eigen::Matrix4d S = H * cov_pred * H.transpose() + observation_cov_;
    Eigen::Matrix4d K = cov_pred * H.transpose() * S.inverse();

    //storage estimation results
    x_est_ = x_pred + K * y;
    cov_est_ = (Eigen::Matrix4d::Identity() - K * H) * cov_pred;

    pos.x() = x_est_(0);
    pos.y() = x_est_(1);
    yaw = x_est_(2);
    cov_xy_th = cov_est_.block(0, 0, 3, 3);

    return true;
}

} //namespace fulanghua

int main(int argc, char *argv[]) {
    ros::init(argc, argv, "pose_estimator");

    ros::NodeHandle nh;
    fulanghua::PoseEstimator estimator(nh);
    estimator.spin();

    return 0;
}
<commit_msg>modified to use valid data of IMU<commit_after>/*
 * Software License Agreement (BSD License)
 *
 * Copyright (c) 2015, Daiki Maekawa and Chiba Institute of Technology.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above
 *    copyright notice, this list of conditions and the following
 *    disclaimer in the documentation and/or other materials provided
 *    with the distribution.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <fulanghua_ekf_2d/pose_estimator.h>

#include <boost/assign.hpp>

#include <Eigen/LU>
#include <Eigen/Dense>

namespace fulanghua {

double normalize_rad(double th) {
    while(th > M_PI) th -= 2 * M_PI;
    while(th < -M_PI) th += 2 * M_PI;

    return th;
}

PoseEstimator::PoseEstimator(ros::NodeHandle &node) :
    enable_gpos_meas_(true),
    update_rate_(100),
    output_frame_("combined_odom"),
    base_frame_("map"),
    x_est_(Eigen::Vector4d::Zero()),
    cov_est_(Eigen::Matrix4d::Identity()),
    pose_pub_(node.advertise<geometry_msgs::PoseWithCovarianceStamped>("self_pose", 10))
{
    ros::NodeHandle nh_private("~");

    nh_private.param("output_frame", output_frame_, output_frame_);
    nh_private.param("base_frame", base_frame_, base_frame_);

    double motion_x_err, motion_y_err, motion_ang_err, motion_vel_err;
    double observation_x_err, observation_y_err, observation_ang_err, observation_vel_err;

    nh_private.param("motion_x_err", motion_x_err, 0.1);
    nh_private.param("motion_y_err", motion_y_err, 0.1);
    nh_private.param("motion_ang_err", motion_ang_err, 0.1);
    nh_private.param("motion_vel_err", motion_vel_err, 0.05);

    nh_private.param("observation_x_err", observation_x_err, 1.5);
    nh_private.param("observation_y_err", observation_y_err, 1.5);
    nh_private.param("observation_ang_err", observation_ang_err, 0.1);
    nh_private.param("observation_vel_err", observation_vel_err, 0.05);

    motion_cov_ << motion_x_err * motion_x_err, 0.0, 0.0, 0.0,
                   0.0, motion_y_err * motion_y_err, 0.0, 0.0,
                   0.0, 0.0, motion_ang_err * motion_ang_err, 0.0,
                   0.0, 0.0, 0.0, motion_vel_err * motion_vel_err;

    observation_cov_ << observation_x_err * observation_x_err, 0.0, 0.0, 0.0,
                       0.0, observation_y_err * observation_y_err, 0.0, 0.0,
                       0.0, 0.0, observation_ang_err * observation_ang_err, 0.0,
                       0.0, 0.0, 0.0, observation_vel_err * observation_vel_err;

    nh_private.param("enable_gpos_meas", enable_gpos_meas_, enable_gpos_meas_);

    imu_sub_ = node.subscribe("imu", 10, &PoseEstimator::imu_callback, this);
    odom_sub_ = node.subscribe("odom", 10, &PoseEstimator::odom_callback, this);

    if(enable_gpos_meas_)
        gpos_meas_sub_ = node.subscribe("meas_gpos", 10, &PoseEstimator::gpos_meas_callback, this);

}

void PoseEstimator::spin() {
    ros::Rate rate(update_rate_);
    ros::Time old_filter_stamp(0);
    bool meas_initialized = false;

    while(ros::ok()) {
        ros::spinOnce();
        rate.sleep();

        if(old_filter_stamp != ros::Time(0) && imu_stamp_ != ros::Time(0) && odom_stamp_ != ros::Time(0)) {
            if(enable_gpos_meas_) {
                if(gpos_meas_stamp_ != ros::Time(0)) meas_initialized = true;
            } else {
                meas_initialized = true;
            }
        }

        if(meas_initialized) {

            ros::Time now = ros::Time::now();
            ros::Time filter_stamp = now;

            filter_stamp = std::min(filter_stamp, odom_stamp_);
            filter_stamp = std::min(filter_stamp, imu_stamp_);

            if(enable_gpos_meas_)
                filter_stamp = std::min(filter_stamp, gpos_meas_stamp_);

            double dt = (now - old_filter_stamp).toSec();
            if(fabs(dt) < 0.0001) continue;

            if((ros::Time::now() - filter_stamp).toSec() > 1.0) {
                ROS_WARN("receive data are too old!");
                continue;
            }

            Eigen::Vector2d est_pos;
            double est_yaw;
            Eigen::Matrix3d est_cov;
            if(!estimate(est_pos, est_yaw, est_cov, filter_stamp, dt)) continue;

            geometry_msgs::PoseWithCovarianceStamped est_pose;
            est_pose.header.stamp = filter_stamp;
            est_pose.header.frame_id = base_frame_;
            est_pose.pose.pose.position.x = est_pos.x();
            est_pose.pose.pose.position.y = est_pos.y();
            est_pose.pose.pose.orientation = tf::createQuaternionMsgFromYaw(est_yaw);

            est_pose.pose.covariance = boost::assign::list_of
                (est_cov(0)) (0) (0) (0) (0) (0)
                (0) (est_cov(1)) (0) (0) (0) (0)
                (0) (0) (999999.9) (0) (0) (0)
                (0) (0) (0) (999999.9) (0) (0)
                (0) (0) (0) (0) (0) (est_cov(2));

            pose_pub_.publish(est_pose);

            geometry_msgs::TransformStamped tran;
            tran.header.stamp = filter_stamp;
            tran.header.frame_id = base_frame_;
            tran.child_frame_id = output_frame_;
            tran.transform.translation.x = est_pose.pose.pose.position.x;
            tran.transform.translation.y = est_pose.pose.pose.position.y;
            tran.transform.translation.z = 0.0;
            tran.transform.rotation = est_pose.pose.pose.orientation;

            tf_broadcaster_.sendTransform(tran);

            old_filter_stamp = now;
        } else {
            old_filter_stamp = ros::Time::now();

            if(transformer_.canTransform(base_frame_, "odom", old_filter_stamp)) {
                transformer_.lookupTransform("odom", base_frame_, old_filter_stamp, old_odom_meas_);
            }
        }
    }
}

bool PoseEstimator::estimate(Eigen::Vector2d &pos, double &yaw, Eigen::Matrix3d &cov_xy_th, const ros::Time &filter_stamp, double dt) {

    tf::StampedTransform odom_meas;
    if(!transformer_.canTransform(base_frame_, "odom", filter_stamp)) {
        ROS_WARN("Failed transform of odom data");
        return false;
    } else {
        transformer_.lookupTransform("odom", base_frame_, filter_stamp, odom_meas);
    }

    double gpos_meas_x, gpos_meas_y;
    if(enable_gpos_meas_) {
        tf::StampedTransform gpos_meas;
        if(!transformer_.canTransform(base_frame_, "gpos_meas", filter_stamp)) {
            ROS_WARN("Failed transform of gpos_meas data");
            return false;
        } else {
            transformer_.lookupTransform("gpos_meas", base_frame_, filter_stamp, gpos_meas);
        }

        gpos_meas_x = gpos_meas.getOrigin().x();
        gpos_meas_y = gpos_meas.getOrigin().y();
    } else {
        gpos_meas_x = odom_meas.getOrigin().x();
        gpos_meas_y = odom_meas.getOrigin().y();
    }

    tf::StampedTransform imu_meas;
    if(!transformer_.canTransform(base_frame_, "imu", filter_stamp)) {
        ROS_WARN("Failed transform of imu data");
        return false;
    } else {
        transformer_.lookupTransform("imu", base_frame_, filter_stamp, imu_meas);
    }

    double odom_linear_x = (odom_meas.getOrigin().x() - old_odom_meas_.getOrigin().x()) / dt;

    double odom_angular_z;
    double tmp_r, tmp_p, odom_yaw;
    odom_meas.getBasis().getEulerYPR(odom_yaw, tmp_p, tmp_r);
    double tmp_old_r, tmp_old_p, old_odom_yaw;
    old_odom_meas_.getBasis().getEulerYPR(old_odom_yaw, tmp_old_p, tmp_old_r);
    odom_angular_z = (odom_yaw - old_odom_yaw) / dt;

    ///< @todo use tf_listener for imu frame
    double imu_roll, imu_pitch, imu_yaw;
    imu_meas.getBasis().getEulerYPR(imu_yaw, imu_pitch, imu_roll);

    //predict
    Eigen::Vector2d u(odom_linear_x, odom_angular_z);
    Eigen::Vector4d x_pred = motion_model(x_est_, u, dt);
    Eigen::Matrix4d JF = jacob_motion_model(x_pred, u, dt);
    Eigen::Matrix4d cov_pred = JF * cov_est_ * JF.transpose() + motion_cov_;

    //update
    Eigen::Vector4d x(gpos_meas_x, gpos_meas_y, imu_yaw, odom_linear_x);
    Eigen::Vector4d z = observation_model(x);
    Eigen::Matrix4d H = jacob_observation_model(x_pred);
    Eigen::Vector4d y = z - observation_model(x_pred);
    y(2) = normalize_rad(y(2));
    Eigen::Matrix4d S = H * cov_pred * H.transpose() + observation_cov_;
    Eigen::Matrix4d K = cov_pred * H.transpose() * S.inverse();

    //storage estimation results
    x_est_ = x_pred + K * y;
    cov_est_ = (Eigen::Matrix4d::Identity() - K * H) * cov_pred;

    pos.x() = x_est_(0);
    pos.y() = x_est_(1);
    yaw = x_est_(2);
    cov_xy_th = cov_est_.block(0, 0, 3, 3);

    return true;
}

} //namespace fulanghua

int main(int argc, char *argv[]) {
    ros::init(argc, argv, "pose_estimator");

    ros::NodeHandle nh;
    fulanghua::PoseEstimator estimator(nh);
    estimator.spin();

    return 0;
}
<|endoftext|>


<commit_before>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Brad van der Laan
 *
 * 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.
 */
#ifndef COMMANDLINEINTERFACE_HPP
#define COMMANDLINEINTERFACE_HPP

#include <QObject>
#include <QMap>
#include <QVariant>
#include <QStringList>
#include "Argument.hpp"
#include "CommandLineInterfaceBuilder.hpp"

namespace Taranis
{
    namespace UnitTest
    {
        class TaranisTestSuite;
    }

    /**
     * @brief The CommandLineInterface class represents a command line interface.
     * Your application will accept command line arguments which are defined in the CommandLineInterface object.
     */
    class CommandLineInterface
    {
        friend class CommandLineInterfaceBuilder;
        friend class UnitTest::TaranisTestSuite;
    public:
        CommandLineInterface() = delete;
        virtual ~CommandLineInterface();

        QString name() const;
        QString version() const;
        QString description() const;
        QStringList arguments() const;

        /**
         * @brief You can use the index operator to access argument values.
         * @param key is the key or name of the argument whose value you are looking for.
         * @return Returns the value of an argument or an invalid QVariant if the argument does not exist.
         */
        QVariant operator[](const QString key) const;

        /**
         * @brief build is a static helper method to easily access a builder of CommandLineInterface objects.
         * @return Returns a command line interface builder.
         */
        static CommandLineInterfaceBuilder build();

    protected:
        explicit CommandLineInterface(const QString applicationName, QStringList arguments, QStringList acceptedArgumentPrefixes);

        /**
         * @brief process will read the input arguments and parse them into Argument objects then execute their callbacks.
         */
        virtual CommandLineInterface& process();

        virtual QString helpMessage() const;
        virtual void doHelpAction() const;
        virtual void doVersionAction() const;
        virtual QString generateTitle() const;
        void addArgument( Argument* arg );
        void setVersion( const QString version );
        void setName( const QString name );
        void setDescription( const QString description );
        void addHelpArguments();
        void setValue( const QString key, const QVariant value );

    private:
        QString m_applicationName;
        QString m_version;
        QString m_description;
        QMap<QString, Argument*> m_arguments;
        QStringList m_inputArguments;
        QStringList m_acceptedArgumentPrefixs;
        static const QString VERSIONARGUMENT;
    };
}

#endif // COMMANDLINEINTERFACE_HPP
<commit_msg>Add comments explaning the examples. This will be used by Doxygen to preface the examples.<commit_after>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Brad van der Laan
 *
 * 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.
 */
#ifndef COMMANDLINEINTERFACE_HPP
#define COMMANDLINEINTERFACE_HPP

#include <QObject>
#include <QMap>
#include <QVariant>
#include <QStringList>
#include "Argument.hpp"
#include "CommandLineInterfaceBuilder.hpp"

namespace Taranis
{
    namespace UnitTest
    {
        class TaranisTestSuite;
    }

    /**
     * @brief The CommandLineInterface class represents a command line interface.
     * Your application will accept command line arguments which are defined in the CommandLineInterface object.
     */
    class CommandLineInterface
    {
        friend class CommandLineInterfaceBuilder;
        friend class UnitTest::TaranisTestSuite;
    public:
        CommandLineInterface() = delete;
        virtual ~CommandLineInterface();

        QString name() const;
        QString version() const;
        QString description() const;
        QStringList arguments() const;

        /**
         * @brief You can use the index operator to access argument values.
         * @param key is the key or name of the argument whose value you are looking for.
         * @return Returns the value of an argument or an invalid QVariant if the argument does not exist.
         */
        QVariant operator[](const QString key) const;

        /**
         * @brief build is a static helper method to easily access a builder of CommandLineInterface objects.
         * @return Returns a command line interface builder.
         */
        static CommandLineInterfaceBuilder build();

    protected:
        explicit CommandLineInterface(const QString applicationName, QStringList arguments, QStringList acceptedArgumentPrefixes);

        /**
         * @brief process will read the input arguments and parse them into Argument objects then execute their callbacks.
         */
        virtual CommandLineInterface& process();

        virtual QString helpMessage() const;
        virtual void doHelpAction() const;
        virtual void doVersionAction() const;
        virtual QString generateTitle() const;
        void addArgument( Argument* arg );
        void setVersion( const QString version );
        void setName( const QString name );
        void setDescription( const QString description );
        void addHelpArguments();
        void setValue( const QString key, const QVariant value );

    private:
        QString m_applicationName;
        QString m_version;
        QString m_description;
        QMap<QString, Argument*> m_arguments;
        QStringList m_inputArguments;
        QStringList m_acceptedArgumentPrefixs;
        static const QString VERSIONARGUMENT;
    };

    /**
     * @example main.example1.cpp
     * This example shows how to construct a CommandLineInterface object using the static CommandLineInterface::build() method
     * and the CommandLineInterfaceBuilder's fluent interface. Next it shows you how to read the value of the flag from the
     * constructed object.
     *
     * If you run this example when the user provides the mouse flag such as -mouse, --mouse, -m, /m, /mouse
     * You see see the output Show Mouse? Yes otherwise you'll see Show Mouse? No.
     */
    /**
     * @example main.example2.cpp
     * This example shows how to construct a CommandLineInterface object using the static CommandLineInterface::build() method
     * and the CommandLineInterfaceBuilder's fluent interface. Next it shows how to provide a call back which would be executed
     * if the user provided in this case the mouse flag.
     *
     * In this example you see that there is no need to hold onto the CommandLineInterface object as the call backs
     * are called automatically after construction.
     *
     * If you run this example when the user provides the mouse flag such as -mouse, --mouse, -m, /m, /mouse
     * You see see the output Show Mouse? Yes otherwise you'll see Show Mouse? No.
     */
    /**
     * @example main.example3.cpp
     * This example shows how to construct a CommandLineInterface object using the static CommandLineInterface::build() method
     * and the CommandLineInterfaceBuilder's fluent interface. Next it shows how to requeste the constructed CommandLineInterface
     * object from the builder. Finally it shows how to access the values the user inputed on the command line.
     *
     * @see main.example1.cpp for a one line way of doing the same thing.
     *
     * If you run this example when the user provides the mouse flag such as -mouse, --mouse, -m, /m, /mouse
     * You see see the output Show Mouse? Yes otherwise you'll see Show Mouse? No.
     */

    /**
     * @example main.example4.cpp
     * This example shows how to construct a CommandLineInterface object using the static CommandLineInterface::build() method
     * then define a command line interface using the With methods in a traditional way. Finally it then shows how
     * to requeste the CommandLineInterface object from the builder before showing how to access the values the user inputed
     * on the command line.
     *
     * If you run this example when the user provides the mouse flag such as -mouse, --mouse, -m, /m, /mouse
     * You see see the output Show Mouse? Yes otherwise you'll see Show Mouse? No.
     */
    /**
     * @example main.example5.cpp
     * This example shows how to construct a CommandLineInterfaceBuilder object then how to use it to constructe a
     * CommandLineInterface object using the With methods. Next it show show to request the CommandLineInterface
     * object from the builder before showing how to access the values the user inputed on the command line.
     *
     * If you run this example when the user provides the mouse flag such as -mouse, --mouse, -m, /m, /mouse
     * You see see the output Show Mouse? Yes otherwise you'll see Show Mouse? No.
     */
    /**
     * @example main.example6.cpp
     * This example shows how to construct a CommandLineInterfaceBuilder object then how to use it to constructe a
     * CommandLineInterface object using the With methods. Next it show show to request the CommandLineInterface
     * object from the builder before showing how to access the values the user inputed on the command line.
     *
     * If you run this example when the user provides the mouse flag such as -mouse, --mouse, -m, /m, /mouse
     * You see see the output Show Mouse? Yes otherwise you'll see Show Mouse? No.
     */
}

#endif // COMMANDLINEINTERFACE_HPP
<|endoftext|>


<commit_before>//
// vtTerrainScene - Container class for all of the terrains loaded
//
// Copyright (c) 2001 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "vtlib/vtlib.h"
#include "TerrainScene.h"
#include "Light.h"
#include "SkyDome.h"
#include "Terrain.h"
#include "TimeEngines.h"

///////////////////////////////////////////////////////////////////////
/**
 * A small engine that allows the SkyDome to stay around the Camera.
 */
class vtSkyTrackEngine : public vtEngine
{
public:
	vtSkyTrackEngine();
	virtual void Eval();
	vtCamera *m_pCamera;
};

vtSkyTrackEngine::vtSkyTrackEngine() : vtEngine()
{
	m_pCamera = NULL;
}

void vtSkyTrackEngine::Eval()
{
	// get the location of the camera and the target (skydome)
	vtTransform *pTarget = (vtTransform *) GetTarget();
	if (!pTarget || !m_pCamera)
		return;
	FPoint3 pos1 = m_pCamera->GetTrans();
	FPoint3 pos2 = pTarget->GetTrans();

	// move the target (skydome) to be centers in XZ on the camera
	pos2.x = pos1.x;
	pos2.z = pos1.z;
	pTarget->SetTrans(pos2);
}

///////////////////////////////////////////////////////////////////////
//
// vtTerrainScene class
//

vtTerrainScene::vtTerrainScene()
{
	horizon_color.Set(0.70f, 0.85f, 1.0f);
	azimuth_color.Set(0.12f, 0.32f, 0.70f);

	m_pSkyDome = NULL;
	m_pFirstTerrain = NULL;
	m_pCurrentTerrain = NULL;
	m_pTime = NULL;
	m_pSkyTrack = NULL;
	m_pSunLight = NULL;
}

vtTerrainScene::~vtTerrainScene()
{
	vtGetScene()->RemoveEngine(m_pTime);
	vtGetScene()->RemoveEngine(m_pSkyTrack);

	delete m_pTime;
	delete m_pSkyTrack;

	while (m_pFirstTerrain)
	{
		vtTerrain *del = m_pFirstTerrain;
		m_pFirstTerrain = m_pFirstTerrain->GetNext();
		delete del;
	}
	m_pFirstTerrain = NULL;
	m_pCurrentTerrain = NULL;
}

void vtTerrainScene::_CreateSkydome(const StringArray &datapath)
{
	if (m_pSkyDome != NULL)
		return;

	// 'bsc' is the Bright Star Catalog
	vtString bsc = FindFileOnPaths(datapath, "Sky/bsc.data");
	vtString sun = FindFileOnPaths(datapath, "Sky/glow2.png");
	vtString moon = FindFileOnPaths(datapath, "Sky/moon5_256.png");

	// create a day-night dome
	m_pSkyDome = new vtSkyDome();
	m_pSkyDome->SetDayColors(horizon_color, azimuth_color);
	m_pSkyDome->SetDawnTimes(5, 0, 7, 0);
	m_pSkyDome->SetDuskTimes(17, 0, 19, 0);

	m_pSkyDome->Create(bsc, 3, 1.0f,	// initially unit radius
		sun, moon);
	m_pSkyDome->SetName2("The Sky");
	m_pAtmosphereGroup->AddChild(m_pSkyDome);

	m_pSkyTrack = new vtSkyTrackEngine();
	m_pSkyTrack->SetName2("Sky-Camera-Following");
	m_pSkyTrack->m_pCamera = vtGetScene()->GetCamera();
	m_pSkyTrack->SetTarget(m_pSkyDome);
	vtGetScene()->AddEngine(m_pSkyTrack);
}

/**
 * Find a terrain whose name begins with a given string.
 */
vtTerrain *vtTerrainScene::FindTerrainByName(const char *name)
{
	int len = strlen(name);
	if (!len)
		return NULL;

	for (vtTerrain *pTerr = m_pFirstTerrain; pTerr; pTerr=pTerr->GetNext())
	{
		if (!strncmp(name, pTerr->GetName(), len))
			return pTerr;
	}
	return NULL;
}

void vtTerrainScene::_CreateEngines(bool bDoSound)
{
	// Set Time in motion
	m_pTime = new TimeEngine(this, 0);
	m_pTime->SetName2("Time");
	m_pTime->SetEnabled(false);
	vtGetScene()->AddEngine(m_pTime);
}

/**
 * Call this method once before adding any terrains, to initialize
 * the vtTerrainScene object.
 */
vtRoot *vtTerrainScene::BeginTerrainScene(bool bDoSound)
{
	_CreateEngines(bDoSound);

	m_pTop = new vtRoot();
	m_pTop->SetName2("All Terrain");

	// create the sun
	vtLight *pLight = new vtLight();
	m_pSunLight = new vtMovLight(pLight);

	// default location: over our right shoulder, pointing downward
	m_pSunLight->Translate1(FPoint3(1000.0f, 1000.0f, 1000.0f));
	m_pSunLight->RotateLocal(FPoint3(0,1,0), PIf/4.0f);
	m_pSunLight->RotateLocal(FPoint3(1,0,0), -PIf/4.0f);
	m_pSunLight->SetName2("SunLight");

	m_pTop->AddChild(m_pSunLight);

	// create sky group - this holds all celestial objects
	m_pAtmosphereGroup = new vtGroup();
	m_pAtmosphereGroup->SetName2("Atmosphere Group");
	m_pTop->AddChild(m_pAtmosphereGroup);

	return m_pTop;
}

/**
 * Adds a terrain to the scene.
 */
void vtTerrainScene::AppendTerrain(vtTerrain *pTerrain)
{
	// add to linked list
	pTerrain->SetNext(m_pFirstTerrain);
	m_pFirstTerrain = pTerrain;
}

/**
 * Call once after you have appended all of your terrains.
 */
void vtTerrainScene::Finish(const StringArray &datapath)
{
	_CreateSkydome(datapath);

	// start out with no scene active
	for (vtTerrain *t = m_pFirstTerrain; t != NULL; t=t->GetNext())
		t->ActivateEngines(false);
}

/**
 * Set the current Terrain for the scene.  There can only be one terrain
 * active a at time.  If you have more than one terrain, you can use this
 * method to switch between them.
 */
void vtTerrainScene::SetTerrain(vtTerrain *pTerrain)
{
	if (m_pCurrentTerrain != NULL)
	{
		// turn off the scene graph of the previous terrain
		m_pCurrentTerrain->Enable(false);

		// turn off the engines specific to the previous terrain
		m_pCurrentTerrain->ActivateEngines(false);
	}
	m_pCurrentTerrain = pTerrain;

	// if setting to no terrain nothing more to do
	if (!pTerrain)
	{
		if (m_pSkyDome != NULL)
			m_pSkyDome->SetEnabled(false);
		return;
	}

	// switch
	m_pTop->AddChild(m_pCurrentTerrain->GetTopGroup());
	m_pCurrentTerrain->Enable(true);

	TParams &param = m_pCurrentTerrain->GetParams();

	// switch to the projection of this terrain
	m_pCurrentTerrain->SetGlobalProjection();

	// move the sky to fit the new current terrain
	m_pSkyDome->SetEnabled(true);
	FRECT world_ext = pTerrain->GetHeightField()->m_WorldExtents;
	float radius = world_ext.Width() * 5.0;
	float max_radius = 450000;
	if (radius > max_radius)
		radius = max_radius;
	m_pSkyDome->SetRadius(radius);

	// Set background color to match the ocean
	vtGetScene()->SetBgColor(m_pCurrentTerrain->GetOceanColor());

	// turn on the engines specific to the new terrain
	m_pCurrentTerrain->ActivateEngines(true);

	// set the time to the time of the new terrain
	int time = param.m_iInitTime * 3600;
	SetTimeOfDay(time, true);

	// setup time engine
	m_pTime->SetTime(time);
	m_pTime->SetRealIncrement(param.m_fTimeSpeed);
	m_pTime->SetEnabled(param.m_bTimeOn);

	// handle the atmosphere
	m_pSkyDome->SetEnabled(param.m_bSky);
	if (param.m_bSky && param.m_strSkyTexture != "")
	{
		vtString filename = "Sky/";
		filename += param.m_strSkyTexture;
		vtString skytex = FindFileOnPaths(vtTerrain::m_DataPaths, filename);
		if (skytex != "")
			m_pSkyDome->SetTexture(skytex);
	}
	SetFog(param.m_bFog);
}

void vtTerrainScene::ToggleFog()
{
	SetFog(!m_bFog);
}

void vtTerrainScene::SetFog(bool fog)
{
	if (!m_pCurrentTerrain)
		return;
	m_bFog = fog;
	if (m_bFog)
	{
		TParams &param = m_pCurrentTerrain->GetParams();
		m_pCurrentTerrain->GetTopGroup()->SetFog(true, 0, param.m_iFogDistance * 1000);
		vtGetScene()->SetBgColor(horizon_color);
	}
	else
	{
		m_pCurrentTerrain->GetTopGroup()->SetFog(false);
		vtGetScene()->SetBgColor(m_pCurrentTerrain->GetOceanColor());
	}
}

void vtTerrainScene::SetTimeOfDay(unsigned int time, bool fFullRefresh)
{
	if (m_pSkyDome)
	{
		m_pSkyDome->SetSunLight(GetSunLight());
		m_pSkyDome->SetTimeOfDay(time, fFullRefresh);
//		m_pSkyDome->ApplyDayColors();
	}
	// TODO? Update the fog color to match the color of the horizon.
}
<commit_msg>gave the main light a name<commit_after>//
// vtTerrainScene - Container class for all of the terrains loaded
//
// Copyright (c) 2001 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "vtlib/vtlib.h"
#include "TerrainScene.h"
#include "Light.h"
#include "SkyDome.h"
#include "Terrain.h"
#include "TimeEngines.h"

///////////////////////////////////////////////////////////////////////
/**
 * A small engine that allows the SkyDome to stay around the Camera.
 */
class vtSkyTrackEngine : public vtEngine
{
public:
	vtSkyTrackEngine();
	virtual void Eval();
	vtCamera *m_pCamera;
};

vtSkyTrackEngine::vtSkyTrackEngine() : vtEngine()
{
	m_pCamera = NULL;
}

void vtSkyTrackEngine::Eval()
{
	// get the location of the camera and the target (skydome)
	vtTransform *pTarget = (vtTransform *) GetTarget();
	if (!pTarget || !m_pCamera)
		return;
	FPoint3 pos1 = m_pCamera->GetTrans();
	FPoint3 pos2 = pTarget->GetTrans();

	// move the target (skydome) to be centers in XZ on the camera
	pos2.x = pos1.x;
	pos2.z = pos1.z;
	pTarget->SetTrans(pos2);
}

///////////////////////////////////////////////////////////////////////
//
// vtTerrainScene class
//

vtTerrainScene::vtTerrainScene()
{
	horizon_color.Set(0.70f, 0.85f, 1.0f);
	azimuth_color.Set(0.12f, 0.32f, 0.70f);

	m_pSkyDome = NULL;
	m_pFirstTerrain = NULL;
	m_pCurrentTerrain = NULL;
	m_pTime = NULL;
	m_pSkyTrack = NULL;
	m_pSunLight = NULL;
}

vtTerrainScene::~vtTerrainScene()
{
	vtGetScene()->RemoveEngine(m_pTime);
	vtGetScene()->RemoveEngine(m_pSkyTrack);

	delete m_pTime;
	delete m_pSkyTrack;

	while (m_pFirstTerrain)
	{
		vtTerrain *del = m_pFirstTerrain;
		m_pFirstTerrain = m_pFirstTerrain->GetNext();
		delete del;
	}
	m_pFirstTerrain = NULL;
	m_pCurrentTerrain = NULL;
}

void vtTerrainScene::_CreateSkydome(const StringArray &datapath)
{
	if (m_pSkyDome != NULL)
		return;

	// 'bsc' is the Bright Star Catalog
	vtString bsc = FindFileOnPaths(datapath, "Sky/bsc.data");
	vtString sun = FindFileOnPaths(datapath, "Sky/glow2.png");
	vtString moon = FindFileOnPaths(datapath, "Sky/moon5_256.png");

	// create a day-night dome
	m_pSkyDome = new vtSkyDome();
	m_pSkyDome->SetDayColors(horizon_color, azimuth_color);
	m_pSkyDome->SetDawnTimes(5, 0, 7, 0);
	m_pSkyDome->SetDuskTimes(17, 0, 19, 0);

	m_pSkyDome->Create(bsc, 3, 1.0f,	// initially unit radius
		sun, moon);
	m_pSkyDome->SetName2("The Sky");
	m_pAtmosphereGroup->AddChild(m_pSkyDome);

	m_pSkyTrack = new vtSkyTrackEngine();
	m_pSkyTrack->SetName2("Sky-Camera-Following");
	m_pSkyTrack->m_pCamera = vtGetScene()->GetCamera();
	m_pSkyTrack->SetTarget(m_pSkyDome);
	vtGetScene()->AddEngine(m_pSkyTrack);
}

/**
 * Find a terrain whose name begins with a given string.
 */
vtTerrain *vtTerrainScene::FindTerrainByName(const char *name)
{
	int len = strlen(name);
	if (!len)
		return NULL;

	for (vtTerrain *pTerr = m_pFirstTerrain; pTerr; pTerr=pTerr->GetNext())
	{
		if (!strncmp(name, pTerr->GetName(), len))
			return pTerr;
	}
	return NULL;
}

void vtTerrainScene::_CreateEngines(bool bDoSound)
{
	// Set Time in motion
	m_pTime = new TimeEngine(this, 0);
	m_pTime->SetName2("Time");
	m_pTime->SetEnabled(false);
	vtGetScene()->AddEngine(m_pTime);
}

/**
 * Call this method once before adding any terrains, to initialize
 * the vtTerrainScene object.
 */
vtRoot *vtTerrainScene::BeginTerrainScene(bool bDoSound)
{
	_CreateEngines(bDoSound);

	m_pTop = new vtRoot();
	m_pTop->SetName2("All Terrain");

	// create the sun
	vtLight *pLight = new vtLight();
	pLight->SetName2("Main Light");
	m_pSunLight = new vtMovLight(pLight);

	// default location: over our right shoulder, pointing downward
	m_pSunLight->Translate1(FPoint3(1000.0f, 1000.0f, 1000.0f));
	m_pSunLight->RotateLocal(FPoint3(0,1,0), PIf/4.0f);
	m_pSunLight->RotateLocal(FPoint3(1,0,0), -PIf/4.0f);
	m_pSunLight->SetName2("SunLight");

	m_pTop->AddChild(m_pSunLight);

	// create sky group - this holds all celestial objects
	m_pAtmosphereGroup = new vtGroup();
	m_pAtmosphereGroup->SetName2("Atmosphere Group");
	m_pTop->AddChild(m_pAtmosphereGroup);

	return m_pTop;
}

/**
 * Adds a terrain to the scene.
 */
void vtTerrainScene::AppendTerrain(vtTerrain *pTerrain)
{
	// add to linked list
	pTerrain->SetNext(m_pFirstTerrain);
	m_pFirstTerrain = pTerrain;
}

/**
 * Call once after you have appended all of your terrains.
 */
void vtTerrainScene::Finish(const StringArray &datapath)
{
	_CreateSkydome(datapath);

	// start out with no scene active
	for (vtTerrain *t = m_pFirstTerrain; t != NULL; t=t->GetNext())
		t->ActivateEngines(false);
}

/**
 * Set the current Terrain for the scene.  There can only be one terrain
 * active a at time.  If you have more than one terrain, you can use this
 * method to switch between them.
 */
void vtTerrainScene::SetTerrain(vtTerrain *pTerrain)
{
	if (m_pCurrentTerrain != NULL)
	{
		// turn off the scene graph of the previous terrain
		m_pCurrentTerrain->Enable(false);

		// turn off the engines specific to the previous terrain
		m_pCurrentTerrain->ActivateEngines(false);
	}
	m_pCurrentTerrain = pTerrain;

	// if setting to no terrain nothing more to do
	if (!pTerrain)
	{
		if (m_pSkyDome != NULL)
			m_pSkyDome->SetEnabled(false);
		return;
	}

	// switch
	m_pTop->AddChild(m_pCurrentTerrain->GetTopGroup());
	m_pCurrentTerrain->Enable(true);

	TParams &param = m_pCurrentTerrain->GetParams();

	// switch to the projection of this terrain
	m_pCurrentTerrain->SetGlobalProjection();

	// move the sky to fit the new current terrain
	m_pSkyDome->SetEnabled(true);
	FRECT world_ext = pTerrain->GetHeightField()->m_WorldExtents;
	float radius = world_ext.Width() * 5.0;
	float max_radius = 450000;
	if (radius > max_radius)
		radius = max_radius;
	m_pSkyDome->SetRadius(radius);

	// Set background color to match the ocean
	vtGetScene()->SetBgColor(m_pCurrentTerrain->GetOceanColor());

	// turn on the engines specific to the new terrain
	m_pCurrentTerrain->ActivateEngines(true);

	// set the time to the time of the new terrain
	int time = param.m_iInitTime * 3600;
	SetTimeOfDay(time, true);

	// setup time engine
	m_pTime->SetTime(time);
	m_pTime->SetRealIncrement(param.m_fTimeSpeed);
	m_pTime->SetEnabled(param.m_bTimeOn);

	// handle the atmosphere
	m_pSkyDome->SetEnabled(param.m_bSky);
	if (param.m_bSky && param.m_strSkyTexture != "")
	{
		vtString filename = "Sky/";
		filename += param.m_strSkyTexture;
		vtString skytex = FindFileOnPaths(vtTerrain::m_DataPaths, filename);
		if (skytex != "")
			m_pSkyDome->SetTexture(skytex);
	}
	SetFog(param.m_bFog);
}

void vtTerrainScene::ToggleFog()
{
	SetFog(!m_bFog);
}

void vtTerrainScene::SetFog(bool fog)
{
	if (!m_pCurrentTerrain)
		return;
	m_bFog = fog;
	if (m_bFog)
	{
		TParams &param = m_pCurrentTerrain->GetParams();
		m_pCurrentTerrain->GetTopGroup()->SetFog(true, 0, param.m_iFogDistance * 1000);
		vtGetScene()->SetBgColor(horizon_color);
	}
	else
	{
		m_pCurrentTerrain->GetTopGroup()->SetFog(false);
		vtGetScene()->SetBgColor(m_pCurrentTerrain->GetOceanColor());
	}
}

void vtTerrainScene::SetTimeOfDay(unsigned int time, bool fFullRefresh)
{
	if (m_pSkyDome)
	{
		m_pSkyDome->SetSunLight(GetSunLight());
		m_pSkyDome->SetTimeOfDay(time, fFullRefresh);
//		m_pSkyDome->ApplyDayColors();
	}
	// TODO? Update the fog color to match the color of the horizon.
}
<|endoftext|>


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

#include <pdal/FileUtils.hpp>

#include <pdal/drivers/las/Reader.hpp>
#include <pdal/drivers/las/Writer.hpp>
#ifdef PDAL_HAVE_ORACLE
#include <pdal/drivers/oci/Writer.hpp>
#include <pdal/drivers/oci/Reader.hpp>
#endif

#include <pdal/filters/Cache.hpp>
#include <pdal/filters/Chipper.hpp>
#include <pdal/filters/Reprojection.hpp>
#include <pdal/filters/Scaling.hpp>

#include <boost/property_tree/xml_parser.hpp>

#include "AppSupport.hpp"

#include "Application.hpp"

using namespace pdal;

class Pc2Pc : public Application
{
public:
    Pc2Pc(int argc, char* argv[]);
    int execute();

private:
    void addSwitches();
    void validateSwitches();

    std::string m_inputFile;
    std::string m_outputFile;
    std::string m_srs;
    bool m_bCompress;
    boost::uint32_t m_chunkSize;
};

Pc2Pc::Pc2Pc(int argc, char* argv[])
    : Application(argc, argv, "pc2pc")
    , m_inputFile("")
    , m_outputFile("")
    , m_srs("")
    , m_bCompress(false)
    , m_chunkSize(0)
{
    return;
}

void Pc2Pc::validateSwitches()
{
    if (m_inputFile == "")
    {
        throw app_usage_error("--input/-i required");
    }

    if (m_outputFile == "")
    {
        throw app_usage_error("--output/-o required");
    }

    return;
}

void Pc2Pc::addSwitches()
{
    namespace po = boost::program_options;

    po::options_description* file_options = new po::options_description("file options");

    file_options->add_options()
        ("input,i", po::value<std::string>(&m_inputFile)->default_value(""), "input file name")
        ("output,o", po::value<std::string>(&m_outputFile)->default_value(""), "output file name")
        ("a_srs", po::value<std::string>(&m_srs)->default_value(""), "Assign output coordinate system (if supported by output format)")
        ("compress,z", po::value<bool>(&m_bCompress)->zero_tokens()->implicit_value(true), "Compress output data (if supported by output format)")
        ("chunk_size", po::value<boost::uint32_t>(&m_chunkSize), "Size of buffer, for blocked/chunked/tiled transfers")
        ;

    addSwitchSet(file_options);
}

int Pc2Pc::execute()
{
    Options readerOptions;
    {
        readerOptions.add<std::string>("filename", m_inputFile);
        readerOptions.add<bool>("debug", isDebug());
        readerOptions.add<boost::uint32_t>("verbose", getVerboseLevel());
    }

    Options writerOptions;
    {
        writerOptions.add<std::string>("filename", m_outputFile);
        writerOptions.add<bool>("debug", isDebug());
        writerOptions.add<boost::uint32_t>("verbose", getVerboseLevel());

        if (m_srs != "")
        {
            writerOptions.add<std::string>("a_srs", m_srs);
        }

        if (m_bCompress)
        {
            writerOptions.add<bool>("compression", true);
        }

        if (m_chunkSize != 0)
        {
            writerOptions.add<boost::uint32_t>("chunk_size", m_chunkSize);
        }
    }

    Stage* stage = AppSupport::makeReader(readerOptions);

    // BUG: I don't know how we could do this...
    // writer.setPointFormat( reader.getPointFormat() );

    Writer* writer = AppSupport::makeWriter(writerOptions, *stage);

    writer->initialize();

    const boost::uint64_t numPointsToRead = stage->getNumPoints();
    boost::scoped_ptr<pdal::UserCallback> callback((numPointsToRead == 0) ?
        (pdal::UserCallback*)(new HeartbeatCallback) :
        (pdal::UserCallback*)(new PercentageCallback));
    writer->setUserCallback(callback.get());

    const boost::uint64_t numPointsRead = writer->write(numPointsToRead);

    std::cout << "Wrote " << numPointsRead << " points\n";

    delete writer;
    delete stage;

    return 0;
}

int main(int argc, char* argv[])
{
    Pc2Pc app(argc, argv);
    return app.run();
}
<commit_msg>add positional arguments support for input/output<commit_after>/******************************************************************************
* Copyright (c) 2011, Michael P. Gerlek (mpg@flaxen.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in
*       the documentation and/or other materials provided
*       with the distribution.
*     * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
*       names of its contributors may be used to endorse or promote
*       products derived from this software without specific prior
*       written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
****************************************************************************/

#include <pdal/FileUtils.hpp>

#include <pdal/drivers/las/Reader.hpp>
#include <pdal/drivers/las/Writer.hpp>
#ifdef PDAL_HAVE_ORACLE
#include <pdal/drivers/oci/Writer.hpp>
#include <pdal/drivers/oci/Reader.hpp>
#endif

#include <pdal/filters/Cache.hpp>
#include <pdal/filters/Chipper.hpp>
#include <pdal/filters/Reprojection.hpp>
#include <pdal/filters/Scaling.hpp>

#include <boost/property_tree/xml_parser.hpp>

#include "AppSupport.hpp"

#include "Application.hpp"

using namespace pdal;

class Pc2Pc : public Application
{
public:
    Pc2Pc(int argc, char* argv[]);
    int execute();

private:
    void addSwitches();
    void validateSwitches();

    std::string m_inputFile;
    std::string m_outputFile;
    std::string m_srs;
    bool m_bCompress;
    boost::uint32_t m_chunkSize;
};

Pc2Pc::Pc2Pc(int argc, char* argv[])
    : Application(argc, argv, "pc2pc")
    , m_inputFile("")
    , m_outputFile("")
    , m_srs("")
    , m_bCompress(false)
    , m_chunkSize(0)
{
    return;
}

void Pc2Pc::validateSwitches()
{
    if (m_inputFile == "")
    {
        throw app_usage_error("--input/-i required");
    }

    if (m_outputFile == "")
    {
        throw app_usage_error("--output/-o required");
    }

    return;
}

void Pc2Pc::addSwitches()
{
    namespace po = boost::program_options;

    po::options_description* file_options = new po::options_description("file options");

    file_options->add_options()
        ("input,i", po::value<std::string>(&m_inputFile)->default_value(""), "input file name")
        ("output,o", po::value<std::string>(&m_outputFile)->default_value(""), "output file name")
        ("a_srs", po::value<std::string>(&m_srs)->default_value(""), "Assign output coordinate system (if supported by output format)")
        ("compress,z", po::value<bool>(&m_bCompress)->zero_tokens()->implicit_value(true), "Compress output data (if supported by output format)")
        ("chunk_size", po::value<boost::uint32_t>(&m_chunkSize), "Size of buffer, for blocked/chunked/tiled transfers")
        ;

    addSwitchSet(file_options);

    addPositionalSwitch("input", 1);
    addPositionalSwitch("output", 1);
}

int Pc2Pc::execute()
{
    Options readerOptions;
    {
        readerOptions.add<std::string>("filename", m_inputFile);
        readerOptions.add<bool>("debug", isDebug());
        readerOptions.add<boost::uint32_t>("verbose", getVerboseLevel());
    }

    Options writerOptions;
    {
        writerOptions.add<std::string>("filename", m_outputFile);
        writerOptions.add<bool>("debug", isDebug());
        writerOptions.add<boost::uint32_t>("verbose", getVerboseLevel());

        if (m_srs != "")
        {
            writerOptions.add<std::string>("a_srs", m_srs);
        }

        if (m_bCompress)
        {
            writerOptions.add<bool>("compression", true);
        }

        if (m_chunkSize != 0)
        {
            writerOptions.add<boost::uint32_t>("chunk_size", m_chunkSize);
        }
    }

    Stage* stage = AppSupport::makeReader(readerOptions);

    // BUG: I don't know how we could do this...
    // writer.setPointFormat( reader.getPointFormat() );

    Writer* writer = AppSupport::makeWriter(writerOptions, *stage);

    writer->initialize();

    const boost::uint64_t numPointsToRead = stage->getNumPoints();
    boost::scoped_ptr<pdal::UserCallback> callback((numPointsToRead == 0) ?
        (pdal::UserCallback*)(new HeartbeatCallback) :
        (pdal::UserCallback*)(new PercentageCallback));
    writer->setUserCallback(callback.get());

    const boost::uint64_t numPointsRead = writer->write(numPointsToRead);

    std::cout << "Wrote " << numPointsRead << " points\n";

    delete writer;
    delete stage;

    return 0;
}

int main(int argc, char* argv[])
{
    Pc2Pc app(argc, argv);
    return app.run();
}
<|endoftext|>


<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2009 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

You may use this sample code for anything you like, it is not covered by the
same license as the rest of the engine.
-----------------------------------------------------------------------------
*/
/**	Generate 3D julia sets and render them as volume texture
	This demonstrates
	   - User generated textures
	   - Procedural volume textures (Julia makes nice dust clouds)
	   - Custom renderables
	@author W.J. van der Laan
*/

#include "SdkSample.h"
#include "SamplePlugin.h"
#include <OgreTexture.h>
#include <OgreHardwarePixelBuffer.h>
#include <OgreTextureManager.h>
#include <OgreLogManager.h>
#include <sstream>

#include "VolumeRenderable.h"
#include "ThingRenderable.h"
#include "Julia.h"

using namespace Ogre;
using namespace OgreBites;

TexturePtr ptex;
SimpleRenderable *vrend;
SimpleRenderable *trend;
Overlay* overlay;
float xtime = 0.0f;
SceneNode *snode,*fnode;
AnimationState* mOgreAnimState = 0;

class _OgreSampleClassExport Sample_VolumeTex : public SdkSample
{
public:
    Sample_VolumeTex()
	{
		mInfo["Title"] = "Volume Textures";
		mInfo["Description"] = "Demonstrates the use of volume textures.";
		mInfo["Thumbnail"] = "thumb_voltex.png";
		mInfo["Category"] = "Unsorted";
	}

protected:
	float global_real, global_imag, global_theta;

    void setupView(void)
	{
		SdkSample::setupView();

		// Create the camera
        mCamera->setPosition(Vector3(220,-2,176));
        mCamera->lookAt(Vector3(0,0,0));
        mCamera->setNearClipDistance(5);
		mCamera->setFixedYawAxis(false);
	}

    void setupContent(void)
    {
		// Check capabilities
		const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities();
        if (!caps->hasCapability(RSC_TEXTURE_3D))
        {
            OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, "Your card does not support 3D textures, so cannot "
                "run this demo. Sorry!",
                "VolTex::createScene");
        }

        // Create dynamic texture
		ptex = TextureManager::getSingleton().createManual(
			"DynaTex","General", TEX_TYPE_3D, 64, 64, 64, 0, PF_A8R8G8B8);

		// Set ambient light
        mSceneMgr->setAmbientLight(ColourValue(0.6, 0.6, 0.6));
		mSceneMgr->setSkyBox(true, "Examples/MorningSkyBox", 50 );

        //mRoot->getRenderSystem()->clearFrameBuffer(FBT_COLOUR, ColourValue(255,255,255,0));

        // Create a light
        Light* l = mSceneMgr->createLight("MainLight");
        l->setDiffuseColour(0.75, 0.75, 0.80);
		l->setSpecularColour(0.9, 0.9, 1);
        l->setPosition(-100,80,50);
		mSceneMgr->getRootSceneNode()->attachObject(l);

		// Create manual material

		// Create volume renderable
		snode = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0,0,0));

        vrend = new VolumeRenderable(32, 750.0f, "DynaTex");
        snode->attachObject( vrend );

		trend = new ThingRenderable(90.0f, 32, 7.5f);
		trend->setMaterial("Examples/VTDarkStuff");
		snode->attachObject(trend);

		// Ogre head node
		fnode = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0,0,0));
		// Load ogre head
		Entity* head = mSceneMgr->createEntity("head", "ogrehead.mesh");
		fnode->attachObject(head);

		// Animation for ogre head
		// Create a track for the light
        Animation* anim = mSceneMgr->createAnimation("OgreTrack", 10);
        // Spline it for nice curves
        anim->setInterpolationMode(Animation::IM_SPLINE);
        // Create a track to animate the camera's node
        NodeAnimationTrack* track = anim->createNodeTrack(0, fnode);
        // Setup keyframes
        TransformKeyFrame* key = track->createNodeKeyFrame(0); // A startposition
        key->setTranslate(Vector3(0.0f, -15.0f, 0.0f));
        key = track->createNodeKeyFrame(5);//B
        key->setTranslate(Vector3(0.0f, 15.0f, 0.0f));
        key = track->createNodeKeyFrame(10);//C
        key->setTranslate(Vector3(0.0f, -15.0f, 0.0f));
        // Create a new animation state to track this
        mOgreAnimState = mSceneMgr->createAnimationState("OgreTrack");
        mOgreAnimState->setEnabled(true);

        //mFountainNode->attachObject(pSys2);

		//Setup defaults
		global_real = 0.4f;
		global_imag = 0.6f;
		global_theta = 0.0f;

		// show GUI
		createControls();

		setDragLook(true);

		generate();
    }

	bool frameRenderingQueued( const FrameEvent& evt )
    {
		xtime += evt.timeSinceLastFrame;
		xtime = fmod(xtime, 10.0f);
		//snode->roll(Degree(evt.timeSinceLastFrame * 20.0f));
		//fnode->roll(Degree(evt.timeSinceLastFrame * 20.0f));
		static_cast<ThingRenderable*>(trend)->addTime(evt.timeSinceLastFrame * 0.05f);
		mOgreAnimState->addTime(evt.timeSinceLastFrame);
		return SdkSample::frameRenderingQueued(evt);
    }

	void cleanupContent(void)
	{
		ptex.setNull();
		delete vrend;
		delete trend;
	}

	void createControls()
	{
		mTrayMgr->createLabel(TL_TOPLEFT, "JuliaParamLabel", "Julia Parameters", 200);
		mTrayMgr->createThickSlider(TL_TOPLEFT, "RealSlider", "Real", 200, 80, -1, 1, 50)->setValue(global_real, false);
		mTrayMgr->createThickSlider(TL_TOPLEFT, "ImagSlider", "Imag", 200, 80, -1, 1, 50)->setValue(global_imag, false);
		mTrayMgr->createThickSlider(TL_TOPLEFT, "ThetaSlider", "Theta", 200, 80, -1, 1, 50)->setValue(global_theta, false);
		mTrayMgr->showCursor();
	}

	void sliderMoved(Slider* slider)
	{
		if (slider->getName() == "RealSlider")
		{
			global_real = slider->getValue();
		}
		else if (slider->getName() == "ImagSlider")
		{
			global_imag = slider->getValue();
		}
		else if (slider->getName() == "ThetaSlider")
		{
			global_theta = slider->getValue();
		}
		generate();
	}

	void generate()
	{
		/* Evaluate julia fractal for each point */
		Julia julia(global_real, global_imag, global_theta);
		const float scale = 2.5;
		const float vcut = 29.0f;
		const float vscale = 1.0f/vcut;

		HardwarePixelBufferSharedPtr buffer = ptex->getBuffer(0, 0);
		Ogre::StringStream d;
		d << "HardwarePixelBuffer " << buffer->getWidth() << " " << buffer->getHeight() << " " << buffer->getDepth();
		LogManager::getSingleton().logMessage(d.str());

		buffer->lock(HardwareBuffer::HBL_NORMAL);
		const PixelBox &pb = buffer->getCurrentLock();
		d.str("");
		d << "PixelBox " << pb.getWidth() << " " << pb.getHeight() << " " << pb.getDepth() << " " << pb.rowPitch << " " << pb.slicePitch << " " << pb.data << " " << PixelUtil::getFormatName(pb.format);
		LogManager::getSingleton().logMessage(d.str());

		Ogre::uint32 *pbptr = static_cast<Ogre::uint32*>(pb.data);
		for(size_t z=pb.front; z<pb.back; z++)
        {
            for(size_t y=pb.top; y<pb.bottom; y++)
            {
                for(size_t x=pb.left; x<pb.right; x++)
                {
                    if(z==pb.front || z==(pb.back-1) || y==pb.top|| y==(pb.bottom-1) ||
						x==pb.left || x==(pb.right-1))
					{
						// On border, must be zero
						pbptr[x] = 0;
                    }
					else
					{
						float val = julia.eval(((float)x/pb.getWidth()-0.5f) * scale,
								((float)y/pb.getHeight()-0.5f) * scale,
								((float)z/pb.getDepth()-0.5f) * scale);
						if(val > vcut)
							val = vcut;

						PixelUtil::packColour((float)x/pb.getWidth(), (float)y/pb.getHeight(), (float)z/pb.getDepth(), (1.0f-(val*vscale))*0.7f, PF_A8R8G8B8, &pbptr[x]);

					}
                }
                pbptr += pb.rowPitch;
            }
            pbptr += pb.getSliceSkip();
        }
		buffer->unlock();
	}
};

SamplePlugin* sp;
Sample* s;

extern "C" _OgreSampleExport void dllStartPlugin()
{
	s = new Sample_VolumeTex;
	sp = OGRE_NEW SamplePlugin(s->getInfo()["Title"] + " Sample");
	sp->addSample(s);
	Root::getSingleton().installPlugin(sp);
}

extern "C" _OgreSampleExport void dllStopPlugin()
{
	Root::getSingleton().uninstallPlugin(sp);
	OGRE_DELETE sp;
	delete s;
}
<commit_msg>Made VolumeTex sample properly cleanup. It was making the sliders have no effect after the first time running the sample. The dynamic texture wasn't being destroyed. Also fixed the yaw axis.<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2009 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

You may use this sample code for anything you like, it is not covered by the
same license as the rest of the engine.
-----------------------------------------------------------------------------
*/
/**	Generate 3D julia sets and render them as volume texture
	This demonstrates
	   - User generated textures
	   - Procedural volume textures (Julia makes nice dust clouds)
	   - Custom renderables
	@author W.J. van der Laan
*/

#include "SdkSample.h"
#include "SamplePlugin.h"
#include <OgreTexture.h>
#include <OgreHardwarePixelBuffer.h>
#include <OgreTextureManager.h>
#include <OgreLogManager.h>
#include <sstream>

#include "VolumeRenderable.h"
#include "ThingRenderable.h"
#include "Julia.h"

using namespace Ogre;
using namespace OgreBites;

TexturePtr ptex;
SimpleRenderable *vrend;
SimpleRenderable *trend;
Overlay* overlay;
float xtime = 0.0f;
SceneNode *snode,*fnode;
AnimationState* mOgreAnimState = 0;

class _OgreSampleClassExport Sample_VolumeTex : public SdkSample
{
public:

    Sample_VolumeTex()
	{
		mInfo["Title"] = "Volume Textures";
		mInfo["Description"] = "Demonstrates the use of volume textures.";
		mInfo["Thumbnail"] = "thumb_voltex.png";
		mInfo["Category"] = "Unsorted";
	}

	void testCapabilities(const RenderSystemCapabilities* caps)
	{
		if (!caps->hasCapability(RSC_TEXTURE_3D))
        {
            OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, "Your card does not support 3D textures, so cannot "
                "run this demo. Sorry!", "Sample_VolumeTex::testCapabilities");
        }
	}

protected:

	float global_real, global_imag, global_theta;

    void setupView(void)
	{
		SdkSample::setupView();

		// Create the camera
        mCamera->setPosition(Vector3(220,-2,176));
        mCamera->lookAt(Vector3(0,0,0));
        mCamera->setNearClipDistance(5);
	}

    void setupContent(void)
    {
        // Create dynamic texture
		ptex = TextureManager::getSingleton().createManual(
			"DynaTex","General", TEX_TYPE_3D, 64, 64, 64, 0, PF_A8R8G8B8);

		// Set ambient light
        mSceneMgr->setAmbientLight(ColourValue(0.6, 0.6, 0.6));
		mSceneMgr->setSkyBox(true, "Examples/MorningSkyBox", 50 );

        //mRoot->getRenderSystem()->clearFrameBuffer(FBT_COLOUR, ColourValue(255,255,255,0));

        // Create a light
        Light* l = mSceneMgr->createLight("MainLight");
        l->setDiffuseColour(0.75, 0.75, 0.80);
		l->setSpecularColour(0.9, 0.9, 1);
        l->setPosition(-100,80,50);
		mSceneMgr->getRootSceneNode()->attachObject(l);

		// Create volume renderable
		snode = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0,0,0));

        vrend = new VolumeRenderable(32, 750.0f, "DynaTex");
        snode->attachObject( vrend );

		trend = new ThingRenderable(90.0f, 32, 7.5f);
		trend->setMaterial("Examples/VTDarkStuff");
		snode->attachObject(trend);

		// Ogre head node
		fnode = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0,0,0));
		// Load ogre head
		Entity* head = mSceneMgr->createEntity("head", "ogrehead.mesh");
		fnode->attachObject(head);

		// Animation for ogre head
		// Create a track for the light
        Animation* anim = mSceneMgr->createAnimation("OgreTrack", 10);
        // Spline it for nice curves
        anim->setInterpolationMode(Animation::IM_SPLINE);
        // Create a track to animate the camera's node
        NodeAnimationTrack* track = anim->createNodeTrack(0, fnode);
        // Setup keyframes
        TransformKeyFrame* key = track->createNodeKeyFrame(0); // A startposition
        key->setTranslate(Vector3(0.0f, -15.0f, 0.0f));
        key = track->createNodeKeyFrame(5);//B
        key->setTranslate(Vector3(0.0f, 15.0f, 0.0f));
        key = track->createNodeKeyFrame(10);//C
        key->setTranslate(Vector3(0.0f, -15.0f, 0.0f));
        // Create a new animation state to track this
        mOgreAnimState = mSceneMgr->createAnimationState("OgreTrack");
        mOgreAnimState->setEnabled(true);

        //mFountainNode->attachObject(pSys2);

		//Setup defaults
		global_real = 0.4f;
		global_imag = 0.6f;
		global_theta = 0.0f;

		// show GUI
		createControls();

		setDragLook(true);

		generate();
    }

	bool frameRenderingQueued( const FrameEvent& evt )
    {
		xtime += evt.timeSinceLastFrame;
		xtime = fmod(xtime, 10.0f);
		//snode->roll(Degree(evt.timeSinceLastFrame * 20.0f));
		//fnode->roll(Degree(evt.timeSinceLastFrame * 20.0f));
		static_cast<ThingRenderable*>(trend)->addTime(evt.timeSinceLastFrame * 0.05f);
		mOgreAnimState->addTime(evt.timeSinceLastFrame);
		return SdkSample::frameRenderingQueued(evt);
    }

	void cleanupContent(void)
	{
		TextureManager::getSingleton().remove("DynaTex");
		delete vrend;
		delete trend;
	}

	void createControls()
	{
		mTrayMgr->createLabel(TL_TOPLEFT, "JuliaParamLabel", "Julia Parameters", 200);
		mTrayMgr->createThickSlider(TL_TOPLEFT, "RealSlider", "Real", 200, 80, -1, 1, 50)->setValue(global_real, false);
		mTrayMgr->createThickSlider(TL_TOPLEFT, "ImagSlider", "Imag", 200, 80, -1, 1, 50)->setValue(global_imag, false);
		mTrayMgr->createThickSlider(TL_TOPLEFT, "ThetaSlider", "Theta", 200, 80, -1, 1, 50)->setValue(global_theta, false);
		mTrayMgr->showCursor();
	}

	void sliderMoved(Slider* slider)
	{
		if (slider->getName() == "RealSlider")
		{
			global_real = slider->getValue();
		}
		else if (slider->getName() == "ImagSlider")
		{
			global_imag = slider->getValue();
		}
		else if (slider->getName() == "ThetaSlider")
		{
			global_theta = slider->getValue();
		}
		generate();
	}

	void generate()
	{
		/* Evaluate julia fractal for each point */
		Julia julia(global_real, global_imag, global_theta);
		const float scale = 2.5;
		const float vcut = 29.0f;
		const float vscale = 1.0f/vcut;

		HardwarePixelBufferSharedPtr buffer = ptex->getBuffer(0, 0);
		Ogre::StringStream d;
		d << "HardwarePixelBuffer " << buffer->getWidth() << " " << buffer->getHeight() << " " << buffer->getDepth();
		LogManager::getSingleton().logMessage(d.str());

		buffer->lock(HardwareBuffer::HBL_NORMAL);
		const PixelBox &pb = buffer->getCurrentLock();
		d.str("");
		d << "PixelBox " << pb.getWidth() << " " << pb.getHeight() << " " << pb.getDepth() << " " << pb.rowPitch << " " << pb.slicePitch << " " << pb.data << " " << PixelUtil::getFormatName(pb.format);
		LogManager::getSingleton().logMessage(d.str());

		Ogre::uint32 *pbptr = static_cast<Ogre::uint32*>(pb.data);
		for(size_t z=pb.front; z<pb.back; z++)
        {
            for(size_t y=pb.top; y<pb.bottom; y++)
            {
                for(size_t x=pb.left; x<pb.right; x++)
                {
                    if(z==pb.front || z==(pb.back-1) || y==pb.top|| y==(pb.bottom-1) ||
						x==pb.left || x==(pb.right-1))
					{
						// On border, must be zero
						pbptr[x] = 0;
                    }
					else
					{
						float val = julia.eval(((float)x/pb.getWidth()-0.5f) * scale,
								((float)y/pb.getHeight()-0.5f) * scale,
								((float)z/pb.getDepth()-0.5f) * scale);
						if(val > vcut)
							val = vcut;

						PixelUtil::packColour((float)x/pb.getWidth(), (float)y/pb.getHeight(), (float)z/pb.getDepth(), (1.0f-(val*vscale))*0.7f, PF_A8R8G8B8, &pbptr[x]);

					}
                }
                pbptr += pb.rowPitch;
            }
            pbptr += pb.getSliceSkip();
        }
		buffer->unlock();
	}
};

SamplePlugin* sp;
Sample* s;

extern "C" _OgreSampleExport void dllStartPlugin()
{
	s = new Sample_VolumeTex;
	sp = OGRE_NEW SamplePlugin(s->getInfo()["Title"] + " Sample");
	sp->addSample(s);
	Root::getSingleton().installPlugin(sp);
}

extern "C" _OgreSampleExport void dllStopPlugin()
{
	Root::getSingleton().uninstallPlugin(sp);
	OGRE_DELETE sp;
	delete s;
}
<|endoftext|>


<commit_before><commit_msg>New values.<commit_after><|endoftext|>