<commit_before>#include "xalt_config.h"
#include <stdio.h>
#include <string.h>
#include <string>
#include "parseLDTrace.h"
#include "xalt_fgets_alloc.h"
#include "insert.h"
#include "xalt_c_utils.h"

void addPath2Set(std::string& path, SET_t** libT)
{
  char* my_realpath = canonicalize_file_name(path.c_str());
  if (my_realpath)
    {
      insert_key_SET(libT, my_realpath);
      my_free(my_realpath,strlen(my_realpath));
    }
}

void parseLDTrace(const char* xaltobj, const char* linkfileFn, SET_t** libT)
{
  std::string path;
  char* buf = NULL;
  size_t sz = 0;

  FILE* fp = fopen(linkfileFn,"r");
  while(xalt_fgets_alloc(fp, &buf, &sz))
    {
      // Remove lines with ':'
      if (strchr(buf,':'))
        continue;

      // Remove the line with the xalt.o file
      if (strstr(buf, xaltobj))
        continue;

      // Remove any lines that start with /tmp/
      // This will ignore files like /tmp/ccT33qQt.o
      char * p = strstr(buf,"/tmp/");
      if (buf == p)
        continue;

      // Ignore all *.o files
      int len = strlen(buf);
      if (len > 2 && strstr(&buf[len-3],".o\n"))
        continue;

      // Ignore librun_submission.a
      if (len > 2 && strstr(buf,"librun_submission.a\n"))
        continue;

      char * start = strchr(buf,'(');
      if (start)
        {
          // Capture the library name in the parens:
          //    -lgcc_s (/usr/lib/gcc/x86_64-linux-gnu/4.8/libgcc_s.so)
          // or
          //    (/usr/lib/x86_64-linux-gnu/libc_nonshared.a)elf-init.oS
          //
          // Note that we are going to ignore
          //    /usr/lib/x86_64-linux-gnu/libc_nonshared.a(elf-init.oS)

          char * p     = strchr(start+1,')');
          if ( start == NULL || p == NULL)
            continue;

          path.assign(start+1, p);
          addPath2Set(path, libT);
          continue;
        }

      // Save everything else (and get rid of the trailing newline!)
      path.assign(buf, len - 1);
      addPath2Set(path, libT);
    }
}

void readFunctionList(const char* fn, SET_t** funcSet)
{
  char*  buf = NULL;
  size_t sz  = 0;

  FILE* fp = fopen(fn,"r");

  // /tmp/ccCZTucS.o: In function `main':
  // /home/mclay/w/xalt/rt/mpi_hello_world.c:10: undefined reference to `MPI_Comm_rank'
  // /home/mclay/w/xalt/rt/mpi_hello_world.c:11: undefined reference to `MPI_Comm_size'
  // /home/mclay/w/xalt/rt/mpi_hello_world.c:16: undefined reference to `MPI_Finalize'

  const char * needle     = "undefined reference to ";
  int          len_needle = strlen(needle);

  while(xalt_fgets_alloc(fp, &buf, &sz))
    {
      // skip all lines that do not have "undefined references to "
      char* start = strstr(buf,needle);
      if (start == NULL)
        continue;

      start += len_needle;

      if (*start == '`')
        start++;
      char*  p   = strchr(start,'\'');
      if (p)
        *p = '\0';
      insert_key_SET(funcSet, start);
    }
  my_free(buf,sz); sz  = 0; buf = NULL;
}
<commit_msg>Add support for ld.gold function tracking<commit_after>#include "xalt_config.h"
#include <stdio.h>
#include <string.h>
#include <string>
#include "parseLDTrace.h"
#include "xalt_fgets_alloc.h"
#include "insert.h"
#include "xalt_c_utils.h"

void addPath2Set(std::string& path, SET_t** libT)
{
  char* my_realpath = canonicalize_file_name(path.c_str());
  if (my_realpath)
    {
      insert_key_SET(libT, my_realpath);
      my_free(my_realpath,strlen(my_realpath));
    }
}

void parseLDTrace(const char* xaltobj, const char* linkfileFn, SET_t** libT)
{
  std::string path;
  char* buf = NULL;
  size_t sz = 0;

  FILE* fp = fopen(linkfileFn,"r");
  while(xalt_fgets_alloc(fp, &buf, &sz))
    {
      // Remove lines with ':'
      if (strchr(buf,':'))
        continue;

      // Remove the line with the xalt.o file
      if (strstr(buf, xaltobj))
        continue;

      // Remove any lines that start with /tmp/
      // This will ignore files like /tmp/ccT33qQt.o
      char * p = strstr(buf,"/tmp/");
      if (buf == p)
        continue;

      // Ignore all *.o files
      int len = strlen(buf);
      if (len > 2 && strstr(&buf[len-3],".o\n"))
        continue;

      // Ignore librun_submission.a
      if (len > 2 && strstr(buf,"librun_submission.a\n"))
        continue;

      char * start = strchr(buf,'(');
      if (start)
        {
          // Capture the library name in the parens:
          //    -lgcc_s (/usr/lib/gcc/x86_64-linux-gnu/4.8/libgcc_s.so)
          // or
          //    (/usr/lib/x86_64-linux-gnu/libc_nonshared.a)elf-init.oS
          //
          // Note that we are going to ignore
          //    /usr/lib/x86_64-linux-gnu/libc_nonshared.a(elf-init.oS)

          char * p     = strchr(start+1,')');
          if ( start == NULL || p == NULL)
            continue;

          path.assign(start+1, p);
          addPath2Set(path, libT);
          continue;
        }

      // Save everything else (and get rid of the trailing newline!)
      path.assign(buf, len - 1);
      addPath2Set(path, libT);
    }
}

void readFunctionList(const char* fn, SET_t** funcSet)
{
  char*  buf = NULL;
  size_t sz  = 0;

  FILE* fp = fopen(fn,"r");

  // /tmp/ccCZTucS.o: In function `main':
  // /home/mclay/w/xalt/rt/mpi_hello_world.c:10: undefined reference to `MPI_Comm_rank'
  // /home/mclay/w/xalt/rt/mpi_hello_world.c:11: undefined reference to `MPI_Comm_size'
  // /home/mclay/w/xalt/rt/mpi_hello_world.c:16: undefined reference to `MPI_Finalize'

  const char * needle     = "undefined reference to ";
  int          len_needle = strlen(needle);

  while(xalt_fgets_alloc(fp, &buf, &sz))
    {
      // skip all lines that do not have "undefined references to "
      char* start = strstr(buf,needle);
      if (start == NULL)
        continue;

      start += len_needle;

      if (*start == '`' || *start == '\'')
        start++;
      char*  p   = strchr(start,'\'');
      if (p)
        *p = '\0';
      insert_key_SET(funcSet, start);
    }
  my_free(buf,sz); sz  = 0; buf = NULL;
}
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004-2019 musikcube team
//
// 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 the author nor the names of other 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 "SndioOut.h"

#include <core/sdk/constants.h>
#include <core/sdk/IPreferences.h>
#include <math.h>
#include <limits.h>
#include <iostream>
#include <unistd.h>
#include <poll.h>

#define BUFFER_COUNT 16
#define ERROR(str) std::cerr << "SndioOut Error: " << str << "\n";
#define INFO(str) std::cerr << "SndioOut Info: " << str << "\n";
#define LOCK() std::unique_lock<std::mutex> lock(this->mutex);
#define WAIT() this->threadEvent.wait(lock);
#define NOTIFY() this->threadEvent.notify_all();

#define STOP() \
  if(started) { \
    if (!sio_stop(handle)) { \
      INFO("failed to stop sndio") \
      quit = true; \
      continue; \
    } \
    else { \
      INFO("stopped handle") \
      started = false; \
   } \
  } \
  else { \
    INFO("already stopped") \
  }

#define START() \
  if(!started) { \
    if (!sio_start(handle)) { \
      INFO("failed to start sndio") \
      quit = true; \
      continue; \
    } \
    else { \
      INFO("started handle") \
      started = true; \
   } \
  } \
  else { \
    INFO("handle already started") \
  }

#define PREF_DEVICE_ID "device_id"

using namespace musik::core::sdk;

static char* deviceId = nullptr;

extern "C" void SetPreferences(musik::core::sdk::IPreferences* prefs) {
    size_t len = prefs->GetString(PREF_DEVICE_ID, nullptr, 0, "");
    if (len > 1) {
        delete[] deviceId;
        deviceId = new char[len];
        prefs->GetString(PREF_DEVICE_ID, deviceId, len, "");
        prefs->Save();
        INFO("setting deviceId to " + std::string(deviceId));
    }
}

static bool waitForDevice(sio_hdl* hdl) {
    INFO("waiting for device")
    int nfds, revents;
    struct pollfd pfds[1];
    do {
        nfds = sio_pollfd(hdl, pfds, POLLOUT);
        if (nfds > 0) {
            if (poll(pfds, nfds, -1) < 0) {
                INFO("poll failed");
                return false;
            }
        }
        revents = sio_revents(hdl, pfds);
        if (revents & POLLHUP) {
            INFO("device disappeared");
            return false;
        }
    } while (!(revents & POLLOUT));
    INFO("done waiting for device")
    return true;
}

SndioOut::SndioOut() {
    INFO("---------- sndout.ctor ----------")
    this->volume = 1.0f;
    this->state = StateStopped;
    this->latency = 0.0;
    this->writeThread.reset(new std::thread(
        std::bind(&SndioOut::WriteLoop, this)));
}

SndioOut::~SndioOut() {
    this->PushCommand(Command::Quit);
    INFO("joining thread")
    this->writeThread->join();
    INFO("thread finished")
}

void SndioOut::Release() {
    delete this;
}

void SndioOut::PushCommand(Command command) {
    //INFO("PushCommand.start")
    {
        LOCK()
        commands.push_back(command);
    }
    NOTIFY()
    //INFO("PushCommand.end")
}

void SndioOut::Pause() {
    this->PushCommand(Command::Pause);
}

void SndioOut::Resume() {
    this->PushCommand(Command::Resume);
}

void SndioOut::SetVolume(double volume) {
    this->volume = volume;
    this->PushCommand(Command::SetVolume);
}

double SndioOut::GetVolume() {
    return this->volume;
}

void SndioOut::Stop() {
    this->PushCommand(Command::Stop);
}

void SndioOut::Drain() {
    this->PushCommand(Command::Drain);
}

IDeviceList* SndioOut::GetDeviceList() {
    return nullptr;
}

bool SndioOut::SetDefaultDevice(const char* deviceId) {
    return false;
}

IDevice* SndioOut::GetDefaultDevice() {
    return nullptr;
}

int SndioOut::Play(IBuffer *buffer, IBufferProvider *provider) {
    std::this_thread::yield();

    if (this->state != StatePlaying) {
        return OutputInvalidState;
    }

    {
        LOCK()
        if (this->CountBuffersWithProvider(provider) >= BUFFER_COUNT) {
            return OutputBufferFull;
        }
        this->buffers.push_back(BufferContext{provider, buffer});
    }

    NOTIFY()
    return OutputBufferWritten;
}

void SndioOut::WriteLoop() {
    bool started = false;
    std::list<BufferContext> toNotify;
    sio_hdl* handle = nullptr;
    sio_par pars = { 0 };
    short* pcm = nullptr;
    long pcmSamples = 0;
    float ditherState = 0.0;
    bool quit = false;
    BufferContext next {nullptr, nullptr};

    /* open the output device. we only do this once */
    const char* device = (::deviceId && strlen(::deviceId)) ? deviceId : nullptr;
    handle = sio_open(device, SIO_PLAY, 0);
    if (handle == nullptr) {
        INFO("failed to init device")
        quit = true;
    }
    else {
        if (!sio_start(handle)) {
            INFO("device opened, but couldn't start")
            quit = true;
        }
        else {
            started = true;
            INFO("device handle initialized")
        }
    }

    while (!quit) {
        /* drain any old buffers (we do this outside of the critical section */
        if (toNotify.size()) {
            INFO("cleaning up dead buffers")
            for (auto& it : toNotify) {
                it.provider->OnBufferProcessed(it.buffer);
            }
            toNotify.clear();
        }

        {
            /* we wait until we have commands to process or samples to play */
            LOCK()
            while (!quit && !this->commands.size() &&
                   (this->state != StatePlaying || !this->buffers.size()))
            {
                //INFO("waiting")
                WAIT()
                //INFO("done waiting")
            }

            if (quit) {
                continue;
            }

            /* process commands */
            for (auto command : this->commands) {
                switch (command) {
                    case Command::Pause: {
                        INFO("command.pause")
                        STOP()
                        this->state = StatePaused;
                    } break;
                    case Command::Resume: {
                        INFO("command.resume")
                        START()
                        this->state = StatePlaying;
                    } break;
                    case Command::Stop: {
                        INFO("command.stop")
                        STOP()
                        std::swap(toNotify, this->buffers);
                        this->state = StateStopped;
                    } break;
                    case Command::SetVolume: {
                        INFO("command.setvolume")
                        if (handle) {
                            sio_setvol(handle, lround(this->volume * SIO_MAXVOL));
                        }
                    } break;
                    case Command::Drain: {
                        INFO("command.drain")
                        STOP()
                        START()
                    } break;
                    case Command::Quit: {
                        quit = true;
                        continue;
                    } break;
                }
            }

            this->commands.clear();

            /* play the next buffer, if it exists */
            if (started &&
                this->state == StatePlaying &&
                this->buffers.size())
            {
                next = this->buffers.front();
                this->buffers.pop_front();
            }
            else {
                //INFO(std::string("state=") + std::to_string((int) this->state));
                //INFO(std::string("count=") + std::to_string((int) this->buffers.size()));
                continue;
            }
        }

        auto buffer = next.buffer;

        if (buffer) {
            /* ensure our output params are setup properly based on this
            buffer's params */
            if (pars.pchan != buffer->Channels() ||
                pars.rate != buffer->SampleRate())
            {
                INFO("updating output params")

                STOP()

                sio_initpar(&pars);
                pars.pchan = buffer->Channels();
                pars.rate = buffer->SampleRate();
                pars.sig = 1;
                pars.le = SIO_LE_NATIVE;
                pars.bits = 16;
                pars.appbufsz = (pars.rate * 250) / 1000;

                if (!sio_setpar(handle, &pars)) {
                    INFO("sio_setpar() failed");
                    quit = true;
                    continue;
                }

                if (!sio_getpar(handle, &pars)) {
                    INFO("sio_getpar() failed");
                    quit = true;
                    continue;
                }

                START()

                this->latency = (double) pars.bufsz / pars.pchan / pars.rate;
            }

            /* allocate PCM buffer, if needed. most of the time we'll be
            able to re-use the previously allocated one. */
            long samples = buffer->Samples();
            if (!pcm || samples > pcmSamples) {
                delete[] pcm;
                pcm = new short[samples];
                pcmSamples = samples;
            }

            /* convert to 16-bit PCM */
            float* src = buffer->BufferPointer();
            short* dst = pcm;
            for (long i = 0; i < samples; i++) {
                float sample = *src;
                if (sample > 1.0f) sample = 1.0f;
                if (sample < -1.0f) sample = -1.0f;
                sample *= SHRT_MAX;

                /* triangle (high pass) dither, based on Audacity's
                implementation */
                float r = (rand() / (float) RAND_MAX - 0.5f);
                sample = sample + r - ditherState;
                ditherState = r;

                *dst = sample;
                ++dst; ++src;
            }

            /* write the entire output buffer. this may require multiple passes;
            that's ok, just loop until we're done */
            char* data = (char*) pcm;
            size_t dataLength = samples * sizeof(short);
            size_t totalWritten = 0;

            {
//              LOCK()
//              INFO("start write")
                while (totalWritten < dataLength) {
                    size_t remaining = dataLength - totalWritten;
                    size_t written = sio_write(handle, data, remaining);
                    if (written == 0) { INFO("failed to write!") break; }
//                  else { std::cerr << "wrote " << written << " of " << remaining << " bytes\n"; }
                    totalWritten += written;
                    data += written;
                }
//              INFO("end write")
            }

            next.provider->OnBufferProcessed(buffer);
        }
    }

    /* done, free remaining buffers and close the handle */
    {
        LOCK()
        std::swap(toNotify, this->buffers);
        this->buffers.clear();
    }

    if (handle) {
        INFO("closing")
        sio_close(handle);
        handle = nullptr;
    }

    for (auto& it : toNotify) {
    INFO("cleaning up dead buffer")
        it.provider->OnBufferProcessed(it.buffer);
    }

    delete[] pcm;
}

double SndioOut::Latency() {
    return this->latency;
}

size_t SndioOut::CountBuffersWithProvider(IBufferProvider* provider) {
    size_t count = 0;
    for (auto& it : this->buffers) {
        if (it.provider == provider) {
            ++count;
        }
    }
    return count;
}

<commit_msg>Removed SndioOut cruft<commit_after>//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004-2019 musikcube team
//
// 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 the author nor the names of other 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 "SndioOut.h"

#include <core/sdk/constants.h>
#include <core/sdk/IPreferences.h>
#include <math.h>
#include <limits.h>
#include <iostream>

#define BUFFER_COUNT 16
#define ERROR(str) std::cerr << "SndioOut Error: " << str << "\n";
#define INFO(str) std::cerr << "SndioOut Info: " << str << "\n";
#define LOCK() std::unique_lock<std::mutex> lock(this->mutex);
#define WAIT() this->threadEvent.wait(lock);
#define NOTIFY() this->threadEvent.notify_all();

#define STOP() \
  if(started) { \
    if (!sio_stop(handle)) { \
      INFO("failed to stop sndio") \
      quit = true; \
      continue; \
    } \
    else { \
      INFO("stopped handle") \
      started = false; \
   } \
  } \
  else { \
    INFO("already stopped") \
  }

#define START() \
  if(!started) { \
    if (!sio_start(handle)) { \
      INFO("failed to start sndio") \
      quit = true; \
      continue; \
    } \
    else { \
      INFO("started handle") \
      started = true; \
   } \
  } \
  else { \
    INFO("handle already started") \
  }

#define PREF_DEVICE_ID "device_id"

using namespace musik::core::sdk;

static char* deviceId = nullptr;

extern "C" void SetPreferences(musik::core::sdk::IPreferences* prefs) {
    size_t len = prefs->GetString(PREF_DEVICE_ID, nullptr, 0, "");
    if (len > 1) {
        delete[] deviceId;
        deviceId = new char[len];
        prefs->GetString(PREF_DEVICE_ID, deviceId, len, "");
        prefs->Save();
        INFO("setting deviceId to " + std::string(deviceId));
    }
}

SndioOut::SndioOut() {
    INFO("---------- sndout.ctor ----------")
    this->volume = 1.0f;
    this->state = StateStopped;
    this->latency = 0.0;
    this->writeThread.reset(new std::thread(
        std::bind(&SndioOut::WriteLoop, this)));
}

SndioOut::~SndioOut() {
    this->PushCommand(Command::Quit);
    INFO("joining thread")
    this->writeThread->join();
    INFO("thread finished")
}

void SndioOut::Release() {
    delete this;
}

void SndioOut::PushCommand(Command command) {
    //INFO("PushCommand.start")
    {
        LOCK()
        commands.push_back(command);
    }
    NOTIFY()
    //INFO("PushCommand.end")
}

void SndioOut::Pause() {
    this->PushCommand(Command::Pause);
}

void SndioOut::Resume() {
    this->PushCommand(Command::Resume);
}

void SndioOut::SetVolume(double volume) {
    this->volume = volume;
    this->PushCommand(Command::SetVolume);
}

double SndioOut::GetVolume() {
    return this->volume;
}

void SndioOut::Stop() {
    this->PushCommand(Command::Stop);
}

void SndioOut::Drain() {
    this->PushCommand(Command::Drain);
}

IDeviceList* SndioOut::GetDeviceList() {
    return nullptr;
}

bool SndioOut::SetDefaultDevice(const char* deviceId) {
    return false;
}

IDevice* SndioOut::GetDefaultDevice() {
    return nullptr;
}

int SndioOut::Play(IBuffer *buffer, IBufferProvider *provider) {
    std::this_thread::yield();

    if (this->state != StatePlaying) {
        return OutputInvalidState;
    }

    {
        LOCK()
        if (this->CountBuffersWithProvider(provider) >= BUFFER_COUNT) {
            return OutputBufferFull;
        }
        this->buffers.push_back(BufferContext{provider, buffer});
    }

    NOTIFY()
    return OutputBufferWritten;
}

void SndioOut::WriteLoop() {
    bool started = false;
    std::list<BufferContext> toNotify;
    sio_hdl* handle = nullptr;
    sio_par pars = { 0 };
    short* pcm = nullptr;
    long pcmSamples = 0;
    float ditherState = 0.0;
    bool quit = false;
    BufferContext next {nullptr, nullptr};

    /* open the output device. we only do this once */
    const char* device = (::deviceId && strlen(::deviceId)) ? deviceId : nullptr;
    handle = sio_open(device, SIO_PLAY, 0);
    if (handle == nullptr) {
        INFO("failed to init device")
        quit = true;
    }
    else {
        if (!sio_start(handle)) {
            INFO("device opened, but couldn't start")
            quit = true;
        }
        else {
            started = true;
            INFO("device handle initialized")
        }
    }

    while (!quit) {
        /* drain any old buffers (we do this outside of the critical section */
        if (toNotify.size()) {
            INFO("cleaning up dead buffers")
            for (auto& it : toNotify) {
                it.provider->OnBufferProcessed(it.buffer);
            }
            toNotify.clear();
        }

        {
            /* we wait until we have commands to process or samples to play */
            LOCK()
            while (!quit && !this->commands.size() &&
                   (this->state != StatePlaying || !this->buffers.size()))
            {
                //INFO("waiting")
                WAIT()
                //INFO("done waiting")
            }

            if (quit) {
                continue;
            }

            /* process commands */
            for (auto command : this->commands) {
                switch (command) {
                    case Command::Pause: {
                        INFO("command.pause")
                        STOP()
                        this->state = StatePaused;
                    } break;
                    case Command::Resume: {
                        INFO("command.resume")
                        START()
                        this->state = StatePlaying;
                    } break;
                    case Command::Stop: {
                        INFO("command.stop")
                        STOP()
                        std::swap(toNotify, this->buffers);
                        this->state = StateStopped;
                    } break;
                    case Command::SetVolume: {
                        INFO("command.setvolume")
                        if (handle) {
                            sio_setvol(handle, lround(this->volume * SIO_MAXVOL));
                        }
                    } break;
                    case Command::Drain: {
                        INFO("command.drain")
                        STOP()
                        START()
                    } break;
                    case Command::Quit: {
                        quit = true;
                        continue;
                    } break;
                }
            }

            this->commands.clear();

            /* play the next buffer, if it exists */
            if (started &&
                this->state == StatePlaying &&
                this->buffers.size())
            {
                next = this->buffers.front();
                this->buffers.pop_front();
            }
            else {
                //INFO(std::string("state=") + std::to_string((int) this->state));
                //INFO(std::string("count=") + std::to_string((int) this->buffers.size()));
                continue;
            }
        }

        auto buffer = next.buffer;

        if (buffer) {
            /* ensure our output params are setup properly based on this
            buffer's params */
            if (pars.pchan != buffer->Channels() ||
                pars.rate != buffer->SampleRate())
            {
                INFO("updating output params")

                STOP()

                sio_initpar(&pars);
                pars.pchan = buffer->Channels();
                pars.rate = buffer->SampleRate();
                pars.sig = 1;
                pars.le = SIO_LE_NATIVE;
                pars.bits = 16;
                pars.appbufsz = (pars.rate * 250) / 1000;

                if (!sio_setpar(handle, &pars)) {
                    INFO("sio_setpar() failed");
                    quit = true;
                    continue;
                }

                if (!sio_getpar(handle, &pars)) {
                    INFO("sio_getpar() failed");
                    quit = true;
                    continue;
                }

                START()

                this->latency = (double) pars.bufsz / pars.pchan / pars.rate;
            }

            /* allocate PCM buffer, if needed. most of the time we'll be
            able to re-use the previously allocated one. */
            long samples = buffer->Samples();
            if (!pcm || samples > pcmSamples) {
                delete[] pcm;
                pcm = new short[samples];
                pcmSamples = samples;
            }

            /* convert to 16-bit PCM */
            float* src = buffer->BufferPointer();
            short* dst = pcm;
            for (long i = 0; i < samples; i++) {
                float sample = *src;
                if (sample > 1.0f) sample = 1.0f;
                if (sample < -1.0f) sample = -1.0f;
                sample *= SHRT_MAX;

                /* triangle (high pass) dither, based on Audacity's
                implementation */
                float r = (rand() / (float) RAND_MAX - 0.5f);
                sample = sample + r - ditherState;
                ditherState = r;

                *dst = sample;
                ++dst; ++src;
            }

            /* write the entire output buffer. this may require multiple passes;
            that's ok, just loop until we're done */
            char* data = (char*) pcm;
            size_t dataLength = samples * sizeof(short);
            size_t totalWritten = 0;

            {
//              LOCK()
//              INFO("start write")
                while (totalWritten < dataLength) {
                    size_t remaining = dataLength - totalWritten;
                    size_t written = sio_write(handle, data, remaining);
                    if (written == 0) { INFO("failed to write!") break; }
//                  else { std::cerr << "wrote " << written << " of " << remaining << " bytes\n"; }
                    totalWritten += written;
                    data += written;
                }
//              INFO("end write")
            }

            next.provider->OnBufferProcessed(buffer);
        }
    }

    /* done, free remaining buffers and close the handle */
    {
        LOCK()
        std::swap(toNotify, this->buffers);
        this->buffers.clear();
    }

    if (handle) {
        INFO("closing")
        sio_close(handle);
        handle = nullptr;
    }

    for (auto& it : toNotify) {
    INFO("cleaning up dead buffer")
        it.provider->OnBufferProcessed(it.buffer);
    }

    delete[] pcm;
}

double SndioOut::Latency() {
    return this->latency;
}

size_t SndioOut::CountBuffersWithProvider(IBufferProvider* provider) {
    size_t count = 0;
    for (auto& it : this->buffers) {
        if (it.provider == provider) {
            ++count;
        }
    }
    return count;
}

<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2003 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#endif

#include "common.h"
#include "ShotUpdate.h"

//
// ShotUpdate
//

void*			ShotUpdate::pack(void* buf) const
{
  buf = nboPackUByte(buf, player);
  buf = nboPackUShort(buf, id);
  buf = nboPackVector(buf, pos);
  buf = nboPackVector(buf, vel);
  buf = nboPackFloat(buf, dt);
  buf = nboPackShort(buf, team);
  return buf;
}

void*			ShotUpdate::unpack(void* buf)
{
  buf = nboUnpackUByte(buf, player);
  buf = nboUnpackUShort(buf, id);
  buf = nboUnpackVector(buf, pos);
  buf = nboUnpackVector(buf, vel);
  buf = nboUnpackFloat(buf, dt);
  short temp = team;
  buf = nboUnpackShort(buf, temp);
  return buf;
}

//
// FiringInfo
//

FiringInfo::FiringInfo()
{
  // do nothing -- must be prepared before use by unpack() or assignment
}

void*			FiringInfo::pack(void* buf) const
{
  buf = shot.pack(buf);
  buf = flagType->pack(buf);
  buf = nboPackFloat(buf, lifetime);
  return buf;
}

void*			FiringInfo::unpack(void* buf)
{
  buf = shot.unpack(buf);
  buf = FlagType::unpack(buf, flagType);
  buf = nboUnpackFloat(buf, lifetime);
 return buf;
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>Yeah, this shoud explain killed by teammate, problem with rabbit and others<commit_after>/* bzflag
 * Copyright (c) 1993 - 2003 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#endif

#include "common.h"
#include "ShotUpdate.h"

//
// ShotUpdate
//

void*			ShotUpdate::pack(void* buf) const
{
  buf = nboPackUByte(buf, player);
  buf = nboPackUShort(buf, id);
  buf = nboPackVector(buf, pos);
  buf = nboPackVector(buf, vel);
  buf = nboPackFloat(buf, dt);
  buf = nboPackShort(buf, team);
  return buf;
}

void*			ShotUpdate::unpack(void* buf)
{
  buf = nboUnpackUByte(buf, player);
  buf = nboUnpackUShort(buf, id);
  buf = nboUnpackVector(buf, pos);
  buf = nboUnpackVector(buf, vel);
  buf = nboUnpackFloat(buf, dt);
  short temp;
  buf = nboUnpackShort(buf, temp);
  team = (TeamColor)temp;
  return buf;
}

//
// FiringInfo
//

FiringInfo::FiringInfo()
{
  // do nothing -- must be prepared before use by unpack() or assignment
}

void*			FiringInfo::pack(void* buf) const
{
  buf = shot.pack(buf);
  buf = flagType->pack(buf);
  buf = nboPackFloat(buf, lifetime);
  return buf;
}

void*			FiringInfo::unpack(void* buf)
{
  buf = shot.unpack(buf);
  buf = FlagType::unpack(buf, flagType);
  buf = nboUnpackFloat(buf, lifetime);
 return buf;
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>#include "IrcCommands.hpp"

#include "messages/MessageBuilder.hpp"
#include "providers/irc/IrcChannel2.hpp"
#include "providers/irc/IrcServer.hpp"
#include "util/Overloaded.hpp"
#include "util/QStringHash.hpp"

namespace chatterino {

Outcome invokeIrcCommand(const QString &commandName, const QString &allParams,
                         IrcChannel &channel)
{
    if (!channel.server())
    {
        return Failure;
    }

    // STATIC MESSAGES
    static auto staticMessages = std::unordered_map<QString, QString>{
        {"join", "/join is not supported. Press ctrl+r to change the "
                 "channel. If required use /raw JOIN #channel."},
        {"part", "/part is not supported. Press ctrl+r to change the "
                 "channel. If required use /raw PART #channel."},
    };
    auto cmd = commandName.toLower();

    if (auto it = staticMessages.find(cmd); it != staticMessages.end())
    {
        channel.addMessage(makeSystemMessage(it->second));
        return Success;
    }

    // CUSTOM COMMANDS
    auto params = allParams.split(' ');
    auto paramsAfter = [&](int i) {
        return params.mid(i + 1).join(' ');
    };

    auto sendRaw = [&](QString str) {
        channel.server()->sendRawMessage(str);
    };

    if (cmd == "msg")
    {
        sendRaw("PRIVMSG " + params[0] + " :" + paramsAfter(0));
    }
    else if (cmd == "away")
    {
        sendRaw("AWAY" + params[0] + " :" + paramsAfter(0));
    }
    else if (cmd == "knock")
    {
        sendRaw("KNOCK #" + params[0] + " " + paramsAfter(0));
    }
    else if (cmd == "kick")
    {
        if (paramsAfter(1).isEmpty())
            sendRaw("KICK " + params[0] + " " + params[1]);
        else
            sendRaw("KICK " + params[0] + " " + params[1] + " :" +
                    paramsAfter(1));
    }
    else if (cmd == "wallops")
    {
        sendRaw("WALLOPS :" + allParams);
    }
    else if (cmd == "raw")
    {
        sendRaw(allParams);
    }
    else
    {
        sendRaw(cmd.toUpper() + " " + allParams);
    }

    return Success;
}

}  // namespace chatterino
<commit_msg>Fixed away command in IRC (#3190)<commit_after>#include "IrcCommands.hpp"

#include "messages/MessageBuilder.hpp"
#include "providers/irc/IrcChannel2.hpp"
#include "providers/irc/IrcServer.hpp"
#include "util/Overloaded.hpp"
#include "util/QStringHash.hpp"

namespace chatterino {

Outcome invokeIrcCommand(const QString &commandName, const QString &allParams,
                         IrcChannel &channel)
{
    if (!channel.server())
    {
        return Failure;
    }

    // STATIC MESSAGES
    static auto staticMessages = std::unordered_map<QString, QString>{
        {"join", "/join is not supported. Press ctrl+r to change the "
                 "channel. If required use /raw JOIN #channel."},
        {"part", "/part is not supported. Press ctrl+r to change the "
                 "channel. If required use /raw PART #channel."},
    };
    auto cmd = commandName.toLower();

    if (auto it = staticMessages.find(cmd); it != staticMessages.end())
    {
        channel.addMessage(makeSystemMessage(it->second));
        return Success;
    }

    // CUSTOM COMMANDS
    auto params = allParams.split(' ');
    auto paramsAfter = [&](int i) {
        return params.mid(i + 1).join(' ');
    };

    auto sendRaw = [&](QString str) {
        channel.server()->sendRawMessage(str);
    };

    if (cmd == "msg")
    {
        sendRaw("PRIVMSG " + params[0] + " :" + paramsAfter(0));
    }
    else if (cmd == "away")
    {
        sendRaw("AWAY " + params[0] + " :" + paramsAfter(0));
    }
    else if (cmd == "knock")
    {
        sendRaw("KNOCK #" + params[0] + " " + paramsAfter(0));
    }
    else if (cmd == "kick")
    {
        if (paramsAfter(1).isEmpty())
            sendRaw("KICK " + params[0] + " " + params[1]);
        else
            sendRaw("KICK " + params[0] + " " + params[1] + " :" +
                    paramsAfter(1));
    }
    else if (cmd == "wallops")
    {
        sendRaw("WALLOPS :" + allParams);
    }
    else if (cmd == "raw")
    {
        sendRaw(allParams);
    }
    else
    {
        sendRaw(cmd.toUpper() + " " + allParams);
    }

    return Success;
}

}  // namespace chatterino
<|endoftext|>


<commit_before>#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/numpy.h>

#include <iostream>

#include "nifty/python/converter.hxx"
#include "nifty/ufd/ufd.hxx"

namespace nifty{
namespace ufd{

    template<class T>
    void exportUfdT(py::module & ufdModule, const std::string & clsName) {

        typedef Ufd<T> UfdType;
        typedef typename UfdType::Index IndexType;

        py::class_<UfdType>(ufdModule, clsName.c_str())
            .def(py::init<const IndexType>(),
               py::arg("numberOfIndices")
            )
            // find for a single element
            .def("find", [](UfdType & self, const T index) {
                return self.find(index);
            })
            .def("find", [](const UfdType & self, const T index) {
                return self.find(index);
            })
            // find vectorized
            .def("find", [](UfdType & self, const marray::PyView<T,1> indices) {
                marray::PyView<IndexType,1> out({indices.shape(0)});
                for(int i = 0; i < indices.shape(0); ++i)
                    out(i) = self.find(indices(i));
                return out;
            })
            .def("find", [](const UfdType & self, const marray::PyView<T,1> indices) {
                marray::PyView<IndexType,1> out({indices.shape(0)});
                for(int i = 0; i < indices.shape(0); ++i)
                    out(i) = self.find(indices(i));
                return out;
            })
            // merge for a single element
            .def("merge", &UfdType::merge)
            // merge vectorized
            .def("merge", [](UfdType & self, marray::PyView<T,2> mergeIndices) {
                NIFTY_CHECK_OP(mergeIndices.shape(1),==,2,"We need pairs of indices for merging!")
                for(int i = 0; i < mergeIndices.shape(0); ++i)
                    self.merge(mergeIndices(i,0), mergeIndices(i,1));
            })
            .def("assign", &UfdType::assign)
            .def("reset", &UfdType::reset)
            .def("insert", &UfdType::insert)
            .def_property_readonly("numberOfElements", &UfdType::numberOfElements)
            .def_property_readonly("numberOfSets", &UfdType::numberOfSets)
            .def("elementLabeling", [](const UfdType & self) {
                marray::PyView<IndexType,1> out({self.numberOfElements()});
                self.elementLabeling(&out(0));
                return out;
            })
            .def("representativesToSets", [](const UfdType & self) {
                std::vector<std::vector<IndexType>> out;
                self.representativesToSets(out);
                return out;
            })
        ;
    }

    void exportUfd(py::module & ufdModule) {
        exportUfdT<uint32_t>(ufdModule, "Ufd_UInt32");
        exportUfdT<uint64_t>(ufdModule, "Ufd_UInt64");
    }

}
}
<commit_msg>adding docstrings structure to export_ufd.cxx<commit_after>#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/numpy.h>

#include <iostream>

#include "nifty/python/converter.hxx"
#include "nifty/ufd/ufd.hxx"

namespace nifty{
namespace ufd{

    template<class T>
    void exportUfdT(py::module & ufdModule, const std::string & clsName) {

        typedef Ufd<T> UfdType;
        typedef typename UfdType::Index IndexType;

        py::class_<UfdType>(ufdModule, clsName.c_str())
            .def(py::init<const IndexType>(),
               py::arg("numberOfIndices"),
                "This function does bla bla bla. \n\n"
                "Detailed....TODO"
            )
            // find for a single element
            .def("find", [](UfdType & self, const T index) {
                return self.find(index);
            },
                py::arg("element2"),
                "Find the representative element of the set that contains the given element (with path compression).\n\n"
                "Detailed....TODO\n\n"
                "Args:\n"
                "   element (int): Element.\n\n"
            )
            .def("find", [](const UfdType & self, const T index) {
                return self.find(index);
            },
                py::arg("element2"),
                "Find the representative element of the set that contains the given element (with path compression).\n\n"
                "Detailed....TODO\n\n"
                "Args:\n"
                "   element (int): Element.\n\n"
            )
            // find vectorized
            .def("find", [](UfdType & self, const marray::PyView<T,1> indices) {
                marray::PyView<IndexType,1> out({indices.shape(0)});
                for(int i = 0; i < indices.shape(0); ++i)
                    out(i) = self.find(indices(i));
                return out;
            },
                py::arg("element2"),
                "Find the representative element of the set that contains the given element (with path compression).\n\n"
                "Detailed....TODO\n\n"
                "Args:\n"
                "   element (int): Element.\n\n"
            )
            .def("find", [](const UfdType & self, const marray::PyView<T,1> indices) {
                marray::PyView<IndexType,1> out({indices.shape(0)});
                for(int i = 0; i < indices.shape(0); ++i)
                    out(i) = self.find(indices(i));
                return out;
            },
                py::arg("element2"),
                "Find the representative element of the set that contains the given element (with path compression).\n\n"
                "Detailed....TODO\n\n"
                "Args:\n"
                "   element (int): Element.\n\n"
            )
            // merge for a single element
            .def("merge", &UfdType::merge,
                py::arg("element1"),
                py::arg("element2"),
                " Merge two elements\n\n"
                "Detailed....TODO\n\n"
                "Args:\n"
                "   element1 (int): Element in the first set.\n"
                "   element2 (int): Element in the first set.\n\n"
                )
            // merge vectorized
            .def("merge", [](UfdType & self, marray::PyView<T,2> mergeIndices) {
                NIFTY_CHECK_OP(mergeIndices.shape(1),==,2,"We need pairs of indices for merging!")
                for(int i = 0; i < mergeIndices.shape(0); ++i)
                    self.merge(mergeIndices(i,0), mergeIndices(i,1));
            },
                " Merge two elements\n\n"
                "Detailed....TODO\n\n"
                "Args:\n"
            )
            .def("assign", &UfdType::assign,
                py::arg("size"),
                "Reset the ufd (to a number of sets each containing one element).\n\n"
                "Detailed....TODO\n\n"
                "Args:\n"
                "   size (int): Number of distinct sets.\n\n"
                )
            .def("reset", &UfdType::reset)
            .def("insert", &UfdType::insert,
                py::arg("number"),
                "Insert a number of new sets, each containing one element.\n\n"
                "Detailed....TODO\n\n"
                "Args:\n"
                "   number (int): Number of sets to insert.\n\n"
                )
            .def_property_readonly("numberOfElements", &UfdType::numberOfElements,
                "returns the number of elements.\n\n"
                "Detailed....TODO\n\n"
                )
            .def_property_readonly("numberOfSets", &UfdType::numberOfSets,
                "returns the number of sets.\n\n"
                "Detailed....TODO\n\n"
                )
            .def("elementLabeling", [](const UfdType & self) {
                marray::PyView<IndexType,1> out({self.numberOfElements()});
                self.elementLabeling(&out(0));
                return out;
            },
                "Output a contiguous labeling of all elements.\n\n"
                "Detailed....TODO\n\n"
            )
            .def("representativesToSets", [](const UfdType & self) {
                std::vector<std::vector<IndexType>> out;
                self.representativesToSets(out);
                return out;
            },
                "returns the number of elements.\n\n"
                "Detailed....TODO\n\n"
            )
        ;
    }

    void exportUfd(py::module & ufdModule) {
        exportUfdT<uint32_t>(ufdModule, "Ufd_UInt32");
        exportUfdT<uint64_t>(ufdModule, "Ufd_UInt64");
    }

}
}
<|endoftext|>


<commit_before>#include "/System/Library/Frameworks/GLUT.framework/Versions/A/Headers/glut.h"
#include "glrenderthread.h"
#include "glframe.h"
#include <math.h>

#include <iostream>
#include <QSound>
using namespace std;

GLRenderThread::GLRenderThread (GLFrame *_GLFrame) :
    QThread (),
    GLFrame_var (_GLFrame)
{
    doRendering = true;
    doResize = false;
    FrameCounter = 0;

    _zoom = -10;
    _current_mouse_pos = QPoint (0,0);

    // added 3 example points
    _point_cloud.push_back (20.0f);
    _point_cloud.push_back (0.0f);
    _point_cloud.push_back (-25.0f);

    _point_cloud.push_back (20.0f);
    _point_cloud.push_back (0.0f);
    _point_cloud.push_back (-15.0f);

    _point_cloud.push_back (20.0f);
    _point_cloud.push_back (0.0f);
    _point_cloud.push_back (-5.0f);
}

void GLRenderThread::resizeViewport (const QSize &size)
{
    w = size.width ();
    h = size.height ();
    doResize = true;
}

void GLRenderThread::stop()
{
    doRendering = false;
}

void GLRenderThread::run ()
{
    GLFrame_var->makeCurrent ();
    GLInit ();

    while (doRendering)
    {
        if (doResize)
        {
            GLResize (w, h);
            doResize = false;
        }
        glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glLoadIdentity();

        paintGL(); // render actual frame

        FrameCounter++;
        GLFrame_var->swapBuffers();

		msleep (16); // wait 16ms => about 60 FPS
    }
}

void GLRenderThread::GLInit (void)
{
    glClearColor (0.05f, 0.05f, 0.2f, 0.0f);

    glShadeModel (GL_SMOOTH); //set the shader to smooth shader
}

void GLRenderThread::GLResize (int width, int height)
{
    glViewport (0, 0, width, height);

    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();

    gluPerspective (45.,((GLfloat)width)/((GLfloat)height),0.1f,1000.0f);

    glMatrixMode (GL_MODELVIEW);
    glLoadIdentity ();

    gluLookAt (0, 0,-1,   // CameraPosition
               0, 0 ,0,   // CameraLookAt
               0, 1 ,0);  // CameraUp
}

void traceGrid ()
{
    // grid
    for (float i = -10; i <= 10; i += 1)
    {
        glBegin (GL_LINES);
            glColor3ub (75, 75, 75);
            glVertex3f (-10, 0, i);
            glVertex3f (10, 0, i);
            glVertex3f (i, 0,-10);
            glVertex3f (i, 0, 10);
        glEnd ();
    }

    // contour
    glBegin (GL_LINES);
    glColor3ub (45, 45, 45);
    glVertex3f (-20, -20, 0);
    glVertex3f (20, -20, 0);
    glVertex3f (20, -20, 0);
    glVertex3f (20, 20, 0);
    glVertex3f (20, 20, 0);
    glVertex3f (-20, 20, 0);
    glVertex3f (-20, 20, 0);
    glVertex3f (-20, -20, 0);
    glEnd ();
    glBegin (GL_LINES);
    glColor3ub (45, 45, 45);
    glVertex3f (0, -20, -20);
    glVertex3f (0, 20, -20);
    glVertex3f (0, 20, -20);
    glVertex3f (0, 20, 20);
    glVertex3f (0, 20, 20);
    glVertex3f (0, -20, 20);
    glVertex3f (0, -20, 20);
    glVertex3f (0, -20, -20);
    glEnd ();
    glBegin (GL_LINES);
    glColor3ub (45, 45, 45);
    glVertex3f (-20, 0, -20);
    glVertex3f (20, 0, -20);
    glVertex3f (20, 0, -20);
    glVertex3f (20, 0, 20);
    glVertex3f (20, 0, 20);
    glVertex3f (-20, 0, 20);
    glVertex3f (-20, 0, 20);
    glVertex3f (-20, 0, -20);
    glEnd ();
    glBegin (GL_LINES);
    glColor3ub (45, 45, 45);
    glVertex3f (0, -20, -20);
    glVertex3f (0, 20, -20);
    glVertex3f (0, 20, -20);
    glVertex3f (0, 20, 20);
    glVertex3f (0, 20, 20);
    glVertex3f (0, -20, 20);
    glVertex3f (0, -20, 20);
    glVertex3f (0, -20, -20);
    glEnd ();

    // main axis
    glBegin (GL_LINES);
    glColor3ub (160, 0, 0);
    glVertex3f (0, 0, 0);
    glVertex3f (0, 0, 10);
    glEnd ();
    glBegin (GL_LINES);
    glColor3ub (0, 160, 0);
    glVertex3f (0, 0, 0);
    glVertex3f (0, 10, 0);
    glEnd ();
    glBegin (GL_LINES);
    glColor3ub (0, 0, 160);
    glVertex3f (0, 0, 0);
    glVertex3f (10, 0, 0);
    glEnd ();
    glBegin (GL_LINES);
    glColor3ub (45, 45, 45);
    glVertex3f (10, 0, 0);
    glVertex3f (20, 0, 0);
    glVertex3f (0, 10, 0);
    glVertex3f (0, 20, 0);
    glVertex3f (0, 0, 10);
    glVertex3f (0, 0, 20);
    glEnd ();
}

void GLRenderThread::paintGL (void)
{
    _delta = QPoint (0,0);

    QPoint q;
    if (GLFrame_var->getCtrlMetaFlag()==true)
    {
        q = _mouse.pos();
        _delta = q - _last_pos;
        _last_pos = q;
    }
    else
    {
        q = _mouse.pos();
        _delta = QPoint (0,0);
        _last_pos = q;
    }

    _current_mouse_pos += _delta;

    //glShadeModel (GL_SMOOTH);
    glTranslatef (0.0f, 0.0f, -60.0f);  // move 60 units into the screen
    glRotatef (FrameCounter, 0.0f, _current_mouse_pos.x() * 0.01f, _current_mouse_pos.y() * 0.01f);

    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Z−Buffer
    // Set the camera orientation :
    glMatrixMode (GL_MODELVIEW) ;
    glLoadIdentity ( ) ;
    gluLookAt (0,  0,-60,  // CameraPosition
               0,  0,  0,  // CameraLookAt
               0,  1,  0); // CameraUp

    // Rotate and zoom camera - Maya-like controls.
    glTranslatef (0, 0, -_zoom);
    // glTranslatef (tx,ty, 0);
    glTranslatef (0, 0, 0);
    glRotatef (-30 - _current_mouse_pos.y() * 0.15f,  1, 0, 0);
    glRotatef (-30 + _current_mouse_pos.x() * 0.1f,   0, 1, 0);

    traceGrid ();

    glEnable (GL_POINT_SMOOTH);
    glPointSize (4.0);

    uint j;
    uint len = _point_cloud.size()/3;
    for (uint i=0; i<len; i++)
    {
        j = i+i+i;
        glBegin (GL_POINTS);
            glVertex3f (_point_cloud[j], _point_cloud[j+1], _point_cloud[j+2]); glColor3f (1.,0.,0.);
        glEnd ();
    }
}

void GLRenderThread::updateZoom (float zoom)
{
    _zoom += zoom * 0.01;
}

void GLRenderThread::setPointCloud (vector<float> &point_cloud)
{
    // remove old test points.
    _point_cloud.pop_back();  _point_cloud.pop_back();  _point_cloud.pop_back();
    _point_cloud.pop_back();  _point_cloud.pop_back();  _point_cloud.pop_back();
    _point_cloud.pop_back();  _point_cloud.pop_back();  _point_cloud.pop_back();

    // add new point cloud
    for (vector <float>::iterator i=point_cloud.begin(); i!=point_cloud.end(); ++i)
    {
        _point_cloud.push_back(*i);
    }

    QSound ping ("/Users/macbookpro/git/JAPCE/ping.wav");
    ping.play();
}
<commit_msg>minor changes to the 3D navigation.<commit_after>#include "/System/Library/Frameworks/GLUT.framework/Versions/A/Headers/glut.h"
#include "glrenderthread.h"
#include "glframe.h"
#include <math.h>

#include <iostream>
#include <QSound>
using namespace std;

GLRenderThread::GLRenderThread (GLFrame *_GLFrame) :
    QThread (),
    GLFrame_var (_GLFrame)
{
    doRendering = true;
    doResize = false;
    FrameCounter = 0;

    _zoom = -10;
    _current_mouse_pos = QPoint (0,0);

    // added 3 example points
    _point_cloud.push_back (20.0f);
    _point_cloud.push_back (0.0f);
    _point_cloud.push_back (-25.0f);

    _point_cloud.push_back (20.0f);
    _point_cloud.push_back (0.0f);
    _point_cloud.push_back (-15.0f);

    _point_cloud.push_back (20.0f);
    _point_cloud.push_back (0.0f);
    _point_cloud.push_back (-5.0f);
}

void GLRenderThread::resizeViewport (const QSize &size)
{
    w = size.width ();
    h = size.height ();
    doResize = true;
}

void GLRenderThread::stop()
{
    doRendering = false;
}

void GLRenderThread::run ()
{
    GLFrame_var->makeCurrent ();
    GLInit ();

    while (doRendering)
    {
        if (doResize)
        {
            GLResize (w, h);
            doResize = false;
        }
        glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glLoadIdentity();

        paintGL(); // render actual frame

        FrameCounter++;
        GLFrame_var->swapBuffers();

		msleep (16); // wait 16ms => about 60 FPS
    }
}

void GLRenderThread::GLInit (void)
{
    glClearColor (0.05f, 0.05f, 0.2f, 0.0f);

    glShadeModel (GL_SMOOTH); //set the shader to smooth shader
}

void GLRenderThread::GLResize (int width, int height)
{
    glViewport (0, 0, width, height);

    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();

    gluPerspective (45.,((GLfloat)width)/((GLfloat)height),0.1f,1000.0f);

    glMatrixMode (GL_MODELVIEW);
    glLoadIdentity ();

    gluLookAt (0, 0,-1,   // CameraPosition
               0, 0 ,0,   // CameraLookAt
               0, 1 ,0);  // CameraUp
}

void traceGrid ()
{
    // grid
    for (float i = -10; i <= 10; i += 1)
    {
        glBegin (GL_LINES);
            glColor3ub (75, 75, 75);
            glVertex3f (-10, 0, i);
            glVertex3f (10, 0, i);
            glVertex3f (i, 0,-10);
            glVertex3f (i, 0, 10);
        glEnd ();
    }

    // contour
    glBegin (GL_LINES);
    glColor3ub (45, 45, 45);
    glVertex3f (-20, -20, 0);
    glVertex3f (20, -20, 0);
    glVertex3f (20, -20, 0);
    glVertex3f (20, 20, 0);
    glVertex3f (20, 20, 0);
    glVertex3f (-20, 20, 0);
    glVertex3f (-20, 20, 0);
    glVertex3f (-20, -20, 0);
    glEnd ();
    glBegin (GL_LINES);
    glColor3ub (45, 45, 45);
    glVertex3f (0, -20, -20);
    glVertex3f (0, 20, -20);
    glVertex3f (0, 20, -20);
    glVertex3f (0, 20, 20);
    glVertex3f (0, 20, 20);
    glVertex3f (0, -20, 20);
    glVertex3f (0, -20, 20);
    glVertex3f (0, -20, -20);
    glEnd ();
    glBegin (GL_LINES);
    glColor3ub (45, 45, 45);
    glVertex3f (-20, 0, -20);
    glVertex3f (20, 0, -20);
    glVertex3f (20, 0, -20);
    glVertex3f (20, 0, 20);
    glVertex3f (20, 0, 20);
    glVertex3f (-20, 0, 20);
    glVertex3f (-20, 0, 20);
    glVertex3f (-20, 0, -20);
    glEnd ();
    glBegin (GL_LINES);
    glColor3ub (45, 45, 45);
    glVertex3f (0, -20, -20);
    glVertex3f (0, 20, -20);
    glVertex3f (0, 20, -20);
    glVertex3f (0, 20, 20);
    glVertex3f (0, 20, 20);
    glVertex3f (0, -20, 20);
    glVertex3f (0, -20, 20);
    glVertex3f (0, -20, -20);
    glEnd ();

    // main axis
    glBegin (GL_LINES);
    glColor3ub (250, 0, 0);
    glVertex3f (0, 0, 0);
    glVertex3f (0, 0, 10);
    glColor3ub (125, 0, 0);
    glVertex3f (0, 0, 10);
    glVertex3f (0, 0, 20);
    glEnd ();
    glBegin (GL_LINES);
    glColor3ub (0, 250, 0);
    glVertex3f (0, 0, 0);
    glVertex3f (0, 10, 0);
    glColor3ub (0, 125, 0);
    glVertex3f (0, 10, 0);
    glVertex3f (0, 20, 0);
    glEnd ();
    glBegin (GL_LINES);
    glColor3ub (0, 0, 250);
    glVertex3f (0, 0, 0);
    glVertex3f (10, 0, 0);
    glColor3ub (0, 0, 125);
    glVertex3f (10, 0, 0);
    glVertex3f (20, 0, 0);
    glEnd ();
}

void GLRenderThread::paintGL (void)
{
    _delta = QPoint (0,0);

    QPoint q;
    if (GLFrame_var->getCtrlMetaFlag()==true)
    {
        q = _mouse.pos();
        _delta = q - _last_pos;
        _last_pos = q;
    }
    else
    {
        q = _mouse.pos();
        _delta = QPoint (0,0);
        _last_pos = q;
    }

    _current_mouse_pos += _delta;

    //glShadeModel (GL_SMOOTH);
    glTranslatef (0.0f, 0.0f, -60.0f);  // move 60 units into the screen
    glRotatef (FrameCounter, 0.0f, _current_mouse_pos.x() * 0.01f, _current_mouse_pos.y() * 0.01f);

    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Z−Buffer
    // Set the camera orientation :
    glMatrixMode (GL_MODELVIEW) ;
    glLoadIdentity ( ) ;
    gluLookAt (0,  0,-60,  // CameraPosition
               0,  0,  0,  // CameraLookAt
               0,  1,  0); // CameraUp

    // Rotate and zoom camera - Maya-like controls.
    glTranslatef (0, 0, -_zoom);
    // glTranslatef (tx,ty, 0);
    glTranslatef (0, 0, 0);
    glRotatef (-30 - _current_mouse_pos.y() * 0.15f,  1, 0, 0);
    glRotatef (-30 + _current_mouse_pos.x() * 0.1f,   0, 1, 0);

    traceGrid ();

    glEnable (GL_POINT_SMOOTH);
    glPointSize (4.0);

    uint j;
    uint len = _point_cloud.size()/3;
    for (uint i=0; i<len; i++)
    {
        j = i+i+i;
        glBegin (GL_POINTS);
            glVertex3f (_point_cloud[j], _point_cloud[j+1], _point_cloud[j+2]); glColor3f (1.,0.,0.);
        glEnd ();
    }
}

void GLRenderThread::updateZoom (float zoom)
{
    _zoom += zoom * 0.01;
}

void GLRenderThread::setPointCloud (vector<float> &point_cloud)
{
    // remove old test points.
    _point_cloud.pop_back();  _point_cloud.pop_back();  _point_cloud.pop_back();
    _point_cloud.pop_back();  _point_cloud.pop_back();  _point_cloud.pop_back();
    _point_cloud.pop_back();  _point_cloud.pop_back();  _point_cloud.pop_back();

    // add new point cloud
    for (vector <float>::iterator i=point_cloud.begin(); i!=point_cloud.end(); ++i)
    {
        _point_cloud.push_back(*i);
    }

    QSound ping ("/Users/macbookpro/git/JAPCE/ping.wav");
    ping.play();
}
<|endoftext|>


<commit_before>#include <imgui/imgui.h>

#include "game_view.h"
#include "editor/asset_browser.h"
#include "editor/asset_compiler.h"
#include "editor/settings.h"
#include "editor/studio_app.h"
#include "editor/utils.h"
#include "editor/world_editor.h"
#include "engine/crc32.h"
#include "engine/engine.h"
#include "engine/geometry.h"
#include "engine/input_system.h"
#include "engine/lua_wrapper.h"
#include "engine/profiler.h"
#include "engine/resource_manager.h"
#include "engine/universe.h"
#include "gui/gui_system.h"
#include "renderer/gpu/gpu.h"
#include "renderer/pipeline.h"
#include "renderer/render_scene.h"
#include "renderer/renderer.h"
#include "renderer/texture.h"

namespace Lumix
{

struct GUIInterface : GUISystem::Interface
{
	explicit GUIInterface(GameView& game_view)
		: m_game_view(game_view)
	{
	}

	Pipeline* getPipeline() override { return m_game_view.m_pipeline; }
	Vec2 getPos() const override { return m_game_view.m_pos; }
	Vec2 getSize() const override { return m_game_view.m_size; }
	void setCursor(OS::CursorType type) { m_game_view.setCursor(type); }
	void enableCursor(bool enable) override { m_game_view.enableIngameCursor(enable); }

	GameView& m_game_view;
};

GameView::GameView(StudioApp& app)
	: m_app(app)
	, m_is_open(false)
	, m_is_fullscreen(false)
	, m_pipeline(nullptr)
	, m_is_mouse_captured(false)
	, m_is_ingame_cursor(false)
	, m_time_multiplier(1.0f)
	, m_paused(false)
	, m_show_stats(false)
	, m_gui_interface(nullptr)
	, m_editor(app.getWorldEditor())
{
	Engine& engine = app.getEngine();
	auto f = &LuaWrapper::wrapMethodClosure<&GameView::forceViewport>;
	LuaWrapper::createSystemClosure(engine.getState(), "GameView", this, "forceViewport", f);

	IAllocator& allocator = app.getAllocator();
	Action* action = LUMIX_NEW(allocator, Action)("Game View", "Toggle game view", "game_view");
	action->func.bind<&GameView::onAction>(this);
	action->is_selected.bind<&GameView::isOpen>(this);
	app.addWindowAction(action);

	Action* fullscreen_action = LUMIX_NEW(allocator, Action)("Game View fullscreen", "Game View fullscreen", "game_view_fullscreen");
	fullscreen_action->func.bind<&GameView::toggleFullscreen>(this);
	app.addAction(fullscreen_action);

	auto* renderer = (Renderer*)engine.getPluginManager().getPlugin("renderer");
	PipelineResource* pres = engine.getResourceManager().load<PipelineResource>(Path("pipelines/main.pln"));
	m_pipeline = Pipeline::create(*renderer, pres, "GAME_VIEW", engine.getAllocator());

	auto* gui = static_cast<GUISystem*>(engine.getPluginManager().getPlugin("gui"));
	if (gui)
	{
		m_gui_interface = LUMIX_NEW(engine.getAllocator(), GUIInterface)(*this);
		gui->setInterface(m_gui_interface);
	}
}

GameView::~GameView()
{
	Engine& engine = m_app.getEngine();
	auto* gui = static_cast<GUISystem*>(engine.getPluginManager().getPlugin("gui"));
	if (gui) {
		gui->setInterface(nullptr);
		LUMIX_DELETE(engine.getAllocator(), m_gui_interface);
	}
	Pipeline::destroy(m_pipeline);
	m_pipeline = nullptr;

}

void GameView::setCursor(OS::CursorType type)
{
	m_cursor_type = type;
}

void GameView::enableIngameCursor(bool enable)
{
	m_is_ingame_cursor = enable;
	if (!m_is_mouse_captured) return;

	OS::showCursor(m_is_ingame_cursor);
}

void GameView::captureMouse(bool capture)
{
	if (m_is_mouse_captured == capture) return;

	m_app.setCursorCaptured(capture);
	m_is_mouse_captured = capture;
	OS::showCursor(!capture || m_is_ingame_cursor);

	if (capture) {
		const OS::Point cp = OS::getMouseScreenPos();
		m_captured_mouse_x = cp.x;
		m_captured_mouse_y = cp.y;
	}
	else {
		OS::unclipCursor();
		OS::setMouseScreenPos(m_captured_mouse_x, m_captured_mouse_y);
	}
}

void GameView::onSettingsLoaded() {
	m_is_open = m_app.getSettings().getValue("is_game_view_open", false);
}

void GameView::onBeforeSettingsSaved() {
	m_app.getSettings().setValue("is_game_view_open", m_is_open);
}

void GameView::onFullscreenGUI()
{
	processInputEvents();

	ImGuiIO& io = ImGui::GetIO();
	bool open = true;
	ImVec2 size = io.DisplaySize;
	ImGui::SetNextWindowPos(ImGui::GetMainViewport()->Pos);
	ImGui::SetNextWindowSize(size);
	if (!ImGui::Begin("game view fullscreen",
		&open,
		ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse |
		ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings))
	{
		ImGui::End();
		return;
	}

	EntityPtr camera = m_pipeline->getScene()->getActiveCamera();
	if (camera.isValid()) {
		Viewport vp = m_pipeline->getScene()->getCameraViewport((EntityRef)camera);
		vp.w = (int)size.x;
		vp.h = (int)size.y;
		m_pipeline->getScene()->setCameraScreenSize((EntityRef)camera, vp.w, vp.h);
		m_pipeline->setViewport(vp);
		m_pipeline->render(false);
		const gpu::TextureHandle texture_handle = m_pipeline->getOutput();
		if (gpu::isOriginBottomLeft())
		{
			ImGui::Image((void*)(uintptr_t)texture_handle.value, size, ImVec2(0, 1), ImVec2(1, 0));
		}
		else
		{
			ImGui::Image((void*)(uintptr_t)texture_handle.value, size);
		}
	}
	else {
		ImGui::Rect(size.x, size.y, 0xff0000FF);
	}
	m_pos = ImGui::GetItemRectMin();
	m_size = ImGui::GetItemRectSize();

	ImGui::End();

	if (m_is_fullscreen && (io.KeysDown[ImGui::GetKeyIndex(ImGuiKey_Escape)] || !m_editor.isGameMode()))
	{
		setFullscreen(false);
	}
}

void GameView::toggleFullscreen()
{
	if (!m_editor.isGameMode()) return;
	setFullscreen(!m_is_fullscreen);
}

void GameView::setFullscreen(bool fullscreen)
{
	captureMouse(fullscreen);
	m_app.setFullscreen(fullscreen);
	m_is_fullscreen = fullscreen;
}

void GameView::onStatsGUI(const ImVec2& view_pos)
{
	if (!m_show_stats || !m_is_open) return;

	float toolbar_height = 24 + ImGui::GetStyle().FramePadding.y * 2;
	ImVec2 v = view_pos;
	v.x += ImGui::GetStyle().FramePadding.x;
	v.y += ImGui::GetStyle().FramePadding.y + toolbar_height;
	ImGui::SetNextWindowPos(v);
	auto col = ImGui::GetStyle().Colors[ImGuiCol_WindowBg];
	col.w = 0.3f;
	ImGui::PushStyleColor(ImGuiCol_WindowBg, col);
	ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings;
	if (ImGui::Begin("###stats_overlay", nullptr, flags)) {
		const auto& stats = m_pipeline->getStats();
		ImGui::LabelText("Draw calls", "%d", stats.draw_call_count);
		ImGui::LabelText("Instances", "%d", stats.instance_count);
		char buf[30];
		toCStringPretty(stats.triangle_count, Span(buf));
		ImGui::LabelText("Triangles", "%s", buf);
		ImGui::LabelText("Resolution", "%dx%d", (int)m_size.x, (int)m_size.y);
	}
	ImGui::End();
	ImGui::PopStyleColor();
}

void GameView::forceViewport(bool enable, int w, int h)
{
	m_forced_viewport.enabled = enable;
	m_forced_viewport.width = w;
	m_forced_viewport.height = h;
}

void GameView::processInputEvents()
{
	if (!m_is_mouse_captured) return;

	Engine& engine = m_app.getEngine();
	InputSystem& input = engine.getInputSystem();
	const OS::Event* events = m_app.getEvents();
	for (int i = 0, c = m_app.getEventsCount(); i < c; ++i) {
		input.injectEvent(events[i], int(m_pos.x), int(m_pos.y));
	}
}

void GameView::controlsGUI() {
	Engine& engine = m_app.getEngine();
	if (ImGui::Checkbox("Pause", &m_paused)) engine.pause(m_paused);
	if (m_paused) {
		ImGui::SameLine();
		if (ImGui::Button("Next frame")) engine.nextFrame();
	}
	ImGui::SameLine();
	ImGui::PushItemWidth(50);
	if (ImGui::DragFloat("Time multiplier", &m_time_multiplier, 0.01f, 0.01f, 30.0f)) {
		engine.setTimeMultiplier(m_time_multiplier);
	}
	ImGui::PopItemWidth();
	if(m_editor.isGameMode()) {
		ImGui::SameLine();
		if (ImGui::Button("Fullscreen")) setFullscreen(true);
	}
	ImGui::SameLine();
	ImGui::Checkbox("Stats", &m_show_stats);
	ImGui::SameLine();
	m_pipeline->callLuaFunction("onGUI");
}

void GameView::onWindowGUI()
{
	PROFILE_FUNCTION();
	if (!m_pipeline->isReady()) {
		captureMouse(false);
		return;
	}

	m_pipeline->setUniverse(m_editor.getUniverse());

	ImGuiIO& io = ImGui::GetIO();
	if (m_is_mouse_captured && (io.KeysDown[ImGui::GetKeyIndex(ImGuiKey_Escape)] || !m_editor.isGameMode())) {
		captureMouse(false);
	}

	const char* window_name = ICON_FA_CAMERA "Game View###game_view";
	if (m_is_mouse_captured) {
		window_name = ICON_FA_CAMERA "Game View (mouse captured)###game_view";
		OS::setCursor(m_cursor_type);
	}

	if (m_is_fullscreen) {
		onFullscreenGUI();
		return;
	}

	if (!m_is_open) {
		captureMouse(false);
		return;
	}

	ImVec2 view_pos;
	bool is_game_view_visible = false;
	ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
	if (ImGui::Begin(window_name, &m_is_open, ImGuiWindowFlags_NoNavInputs)) {
		is_game_view_visible = true;
		view_pos = ImGui::GetCursorScreenPos();

		const ImVec2 content_min = view_pos;
		ImVec2 size = ImGui::GetContentRegionAvail();
		size.y -= ImGui::GetTextLineHeightWithSpacing();
		ImVec2 content_max(content_min.x + size.x, content_min.y + size.y);
		if (m_forced_viewport.enabled) size = { (float)m_forced_viewport.width, (float)m_forced_viewport.height };
		if (size.x > 0 && size.y > 0) {
			RenderScene* scene = m_pipeline->getScene();
			const EntityPtr camera = scene->getActiveCamera();
			Viewport vp;
			if (camera.isValid()) {
				vp = scene->getCameraViewport((EntityRef)camera);
				vp.w = (int)size.x;
				vp.h = (int)size.y;
				scene->setCameraScreenSize((EntityRef)camera, vp.w, vp.h);
			}
			else {
				vp.w = (int)size.x;
				vp.h = (int)size.y;
				vp.fov = degreesToRadians(90.f);
				vp.is_ortho = false;
				vp.far = 10'000.f;
				vp.near = 1.f;
				vp.pos = DVec3(0);
				vp.rot = Quat(0, 0, 0, 1);
			}
			m_pipeline->setViewport(vp);
			m_pipeline->render(false);
			const gpu::TextureHandle texture_handle = m_pipeline->getOutput();

			if (texture_handle.isValid()) {
				if (gpu::isOriginBottomLeft()) {
					ImGui::Image((void*)(uintptr_t)texture_handle.value, size, ImVec2(0, 1), ImVec2(1, 0));
				}
				else {
					ImGui::Image((void*)(uintptr_t)texture_handle.value, size);
				}
			}
			else {
				ImGui::Rect(size.x, size.y, 0xffFF00FF);
			}
			const bool is_hovered = ImGui::IsItemHovered();
			if (is_hovered && ImGui::IsMouseClicked(0) && m_editor.isGameMode()) captureMouse(true);
			m_pos = ImGui::GetItemRectMin();
			m_size = ImGui::GetItemRectSize();

			if (m_is_mouse_captured && m_is_ingame_cursor) {
				OS::clipCursor((int)m_pos.x, (int)m_pos.y, (int)m_size.x, (int)m_size.y);
			}

			processInputEvents();
			controlsGUI();
		}

	}
	if (m_is_mouse_captured && OS::getFocused() != ImGui::GetWindowViewport()->PlatformHandle) captureMouse(false);
	ImGui::End();
	ImGui::PopStyleVar();
	if (is_game_view_visible) onStatsGUI(view_pos);
}

} // namespace Lumix
<commit_msg>mouse cursor moves on desktop when captured by game view - fixed<commit_after>#include <imgui/imgui.h>

#include "game_view.h"
#include "editor/asset_browser.h"
#include "editor/asset_compiler.h"
#include "editor/settings.h"
#include "editor/studio_app.h"
#include "editor/utils.h"
#include "editor/world_editor.h"
#include "engine/crc32.h"
#include "engine/engine.h"
#include "engine/geometry.h"
#include "engine/input_system.h"
#include "engine/lua_wrapper.h"
#include "engine/profiler.h"
#include "engine/resource_manager.h"
#include "engine/universe.h"
#include "gui/gui_system.h"
#include "renderer/gpu/gpu.h"
#include "renderer/pipeline.h"
#include "renderer/render_scene.h"
#include "renderer/renderer.h"
#include "renderer/texture.h"

namespace Lumix
{

struct GUIInterface : GUISystem::Interface
{
	explicit GUIInterface(GameView& game_view)
		: m_game_view(game_view)
	{
	}

	Pipeline* getPipeline() override { return m_game_view.m_pipeline; }
	Vec2 getPos() const override { return m_game_view.m_pos; }
	Vec2 getSize() const override { return m_game_view.m_size; }
	void setCursor(OS::CursorType type) { m_game_view.setCursor(type); }
	void enableCursor(bool enable) override { m_game_view.enableIngameCursor(enable); }

	GameView& m_game_view;
};

GameView::GameView(StudioApp& app)
	: m_app(app)
	, m_is_open(false)
	, m_is_fullscreen(false)
	, m_pipeline(nullptr)
	, m_is_mouse_captured(false)
	, m_is_ingame_cursor(false)
	, m_time_multiplier(1.0f)
	, m_paused(false)
	, m_show_stats(false)
	, m_gui_interface(nullptr)
	, m_editor(app.getWorldEditor())
{
	Engine& engine = app.getEngine();
	auto f = &LuaWrapper::wrapMethodClosure<&GameView::forceViewport>;
	LuaWrapper::createSystemClosure(engine.getState(), "GameView", this, "forceViewport", f);

	IAllocator& allocator = app.getAllocator();
	Action* action = LUMIX_NEW(allocator, Action)("Game View", "Toggle game view", "game_view");
	action->func.bind<&GameView::onAction>(this);
	action->is_selected.bind<&GameView::isOpen>(this);
	app.addWindowAction(action);

	Action* fullscreen_action = LUMIX_NEW(allocator, Action)("Game View fullscreen", "Game View fullscreen", "game_view_fullscreen");
	fullscreen_action->func.bind<&GameView::toggleFullscreen>(this);
	app.addAction(fullscreen_action);

	auto* renderer = (Renderer*)engine.getPluginManager().getPlugin("renderer");
	PipelineResource* pres = engine.getResourceManager().load<PipelineResource>(Path("pipelines/main.pln"));
	m_pipeline = Pipeline::create(*renderer, pres, "GAME_VIEW", engine.getAllocator());

	auto* gui = static_cast<GUISystem*>(engine.getPluginManager().getPlugin("gui"));
	if (gui)
	{
		m_gui_interface = LUMIX_NEW(engine.getAllocator(), GUIInterface)(*this);
		gui->setInterface(m_gui_interface);
	}
}

GameView::~GameView()
{
	Engine& engine = m_app.getEngine();
	auto* gui = static_cast<GUISystem*>(engine.getPluginManager().getPlugin("gui"));
	if (gui) {
		gui->setInterface(nullptr);
		LUMIX_DELETE(engine.getAllocator(), m_gui_interface);
	}
	Pipeline::destroy(m_pipeline);
	m_pipeline = nullptr;

}

void GameView::setCursor(OS::CursorType type)
{
	m_cursor_type = type;
}

void GameView::enableIngameCursor(bool enable)
{
	m_is_ingame_cursor = enable;
	if (!m_is_mouse_captured) return;

	OS::showCursor(m_is_ingame_cursor);
}

void GameView::captureMouse(bool capture)
{
	if (m_is_mouse_captured == capture) return;

	m_app.setCursorCaptured(capture);
	m_is_mouse_captured = capture;
	OS::showCursor(!capture || m_is_ingame_cursor);

	if (capture) {
		const OS::Point cp = OS::getMouseScreenPos();
		m_captured_mouse_x = cp.x;
		m_captured_mouse_y = cp.y;
	}
	else {
		OS::unclipCursor();
		OS::setMouseScreenPos(m_captured_mouse_x, m_captured_mouse_y);
	}
}

void GameView::onSettingsLoaded() {
	m_is_open = m_app.getSettings().getValue("is_game_view_open", false);
}

void GameView::onBeforeSettingsSaved() {
	m_app.getSettings().setValue("is_game_view_open", m_is_open);
}

void GameView::onFullscreenGUI()
{
	processInputEvents();

	ImGuiIO& io = ImGui::GetIO();
	bool open = true;
	ImVec2 size = io.DisplaySize;
	ImGui::SetNextWindowPos(ImGui::GetMainViewport()->Pos);
	ImGui::SetNextWindowSize(size);
	if (!ImGui::Begin("game view fullscreen",
		&open,
		ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse |
		ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings))
	{
		ImGui::End();
		return;
	}

	EntityPtr camera = m_pipeline->getScene()->getActiveCamera();
	if (camera.isValid()) {
		Viewport vp = m_pipeline->getScene()->getCameraViewport((EntityRef)camera);
		vp.w = (int)size.x;
		vp.h = (int)size.y;
		m_pipeline->getScene()->setCameraScreenSize((EntityRef)camera, vp.w, vp.h);
		m_pipeline->setViewport(vp);
		m_pipeline->render(false);
		const gpu::TextureHandle texture_handle = m_pipeline->getOutput();
		if (gpu::isOriginBottomLeft())
		{
			ImGui::Image((void*)(uintptr_t)texture_handle.value, size, ImVec2(0, 1), ImVec2(1, 0));
		}
		else
		{
			ImGui::Image((void*)(uintptr_t)texture_handle.value, size);
		}
	}
	else {
		ImGui::Rect(size.x, size.y, 0xff0000FF);
	}
	m_pos = ImGui::GetItemRectMin();
	m_size = ImGui::GetItemRectSize();

	ImGui::End();

	if (m_is_fullscreen && (io.KeysDown[ImGui::GetKeyIndex(ImGuiKey_Escape)] || !m_editor.isGameMode()))
	{
		setFullscreen(false);
	}
}

void GameView::toggleFullscreen()
{
	if (!m_editor.isGameMode()) return;
	setFullscreen(!m_is_fullscreen);
}

void GameView::setFullscreen(bool fullscreen)
{
	captureMouse(fullscreen);
	m_app.setFullscreen(fullscreen);
	m_is_fullscreen = fullscreen;
}

void GameView::onStatsGUI(const ImVec2& view_pos)
{
	if (!m_show_stats || !m_is_open) return;

	float toolbar_height = 24 + ImGui::GetStyle().FramePadding.y * 2;
	ImVec2 v = view_pos;
	v.x += ImGui::GetStyle().FramePadding.x;
	v.y += ImGui::GetStyle().FramePadding.y + toolbar_height;
	ImGui::SetNextWindowPos(v);
	auto col = ImGui::GetStyle().Colors[ImGuiCol_WindowBg];
	col.w = 0.3f;
	ImGui::PushStyleColor(ImGuiCol_WindowBg, col);
	ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings;
	if (ImGui::Begin("###stats_overlay", nullptr, flags)) {
		const auto& stats = m_pipeline->getStats();
		ImGui::LabelText("Draw calls", "%d", stats.draw_call_count);
		ImGui::LabelText("Instances", "%d", stats.instance_count);
		char buf[30];
		toCStringPretty(stats.triangle_count, Span(buf));
		ImGui::LabelText("Triangles", "%s", buf);
		ImGui::LabelText("Resolution", "%dx%d", (int)m_size.x, (int)m_size.y);
	}
	ImGui::End();
	ImGui::PopStyleColor();
}

void GameView::forceViewport(bool enable, int w, int h)
{
	m_forced_viewport.enabled = enable;
	m_forced_viewport.width = w;
	m_forced_viewport.height = h;
}

void GameView::processInputEvents()
{
	if (!m_is_mouse_captured) return;

	Engine& engine = m_app.getEngine();
	InputSystem& input = engine.getInputSystem();
	const OS::Event* events = m_app.getEvents();
	for (int i = 0, c = m_app.getEventsCount(); i < c; ++i) {
		input.injectEvent(events[i], int(m_pos.x), int(m_pos.y));
	}
}

void GameView::controlsGUI() {
	Engine& engine = m_app.getEngine();
	if (ImGui::Checkbox("Pause", &m_paused)) engine.pause(m_paused);
	if (m_paused) {
		ImGui::SameLine();
		if (ImGui::Button("Next frame")) engine.nextFrame();
	}
	ImGui::SameLine();
	ImGui::PushItemWidth(50);
	if (ImGui::DragFloat("Time multiplier", &m_time_multiplier, 0.01f, 0.01f, 30.0f)) {
		engine.setTimeMultiplier(m_time_multiplier);
	}
	ImGui::PopItemWidth();
	if(m_editor.isGameMode()) {
		ImGui::SameLine();
		if (ImGui::Button("Fullscreen")) setFullscreen(true);
	}
	ImGui::SameLine();
	ImGui::Checkbox("Stats", &m_show_stats);
	ImGui::SameLine();
	m_pipeline->callLuaFunction("onGUI");
}

void GameView::onWindowGUI()
{
	PROFILE_FUNCTION();
	if (!m_pipeline->isReady()) {
		captureMouse(false);
		return;
	}

	m_pipeline->setUniverse(m_editor.getUniverse());

	ImGuiIO& io = ImGui::GetIO();
	if (m_is_mouse_captured && (io.KeysDown[ImGui::GetKeyIndex(ImGuiKey_Escape)] || !m_editor.isGameMode())) {
		captureMouse(false);
	}

	const char* window_name = ICON_FA_CAMERA "Game View###game_view";
	if (m_is_mouse_captured) {
		window_name = ICON_FA_CAMERA "Game View (mouse captured)###game_view";
		OS::setCursor(m_cursor_type);
	}

	if (m_is_fullscreen) {
		onFullscreenGUI();
		return;
	}

	if (!m_is_open) {
		captureMouse(false);
		return;
	}

	ImVec2 view_pos;
	bool is_game_view_visible = false;
	ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
	if (ImGui::Begin(window_name, &m_is_open, ImGuiWindowFlags_NoNavInputs)) {
		is_game_view_visible = true;
		view_pos = ImGui::GetCursorScreenPos();

		const ImVec2 content_min = view_pos;
		ImVec2 size = ImGui::GetContentRegionAvail();
		size.y -= ImGui::GetTextLineHeightWithSpacing();
		ImVec2 content_max(content_min.x + size.x, content_min.y + size.y);
		if (m_forced_viewport.enabled) size = { (float)m_forced_viewport.width, (float)m_forced_viewport.height };
		if (size.x > 0 && size.y > 0) {
			RenderScene* scene = m_pipeline->getScene();
			const EntityPtr camera = scene->getActiveCamera();
			Viewport vp;
			if (camera.isValid()) {
				vp = scene->getCameraViewport((EntityRef)camera);
				vp.w = (int)size.x;
				vp.h = (int)size.y;
				scene->setCameraScreenSize((EntityRef)camera, vp.w, vp.h);
			}
			else {
				vp.w = (int)size.x;
				vp.h = (int)size.y;
				vp.fov = degreesToRadians(90.f);
				vp.is_ortho = false;
				vp.far = 10'000.f;
				vp.near = 1.f;
				vp.pos = DVec3(0);
				vp.rot = Quat(0, 0, 0, 1);
			}
			m_pipeline->setViewport(vp);
			m_pipeline->render(false);
			const gpu::TextureHandle texture_handle = m_pipeline->getOutput();

			if (texture_handle.isValid()) {
				if (gpu::isOriginBottomLeft()) {
					ImGui::Image((void*)(uintptr_t)texture_handle.value, size, ImVec2(0, 1), ImVec2(1, 0));
				}
				else {
					ImGui::Image((void*)(uintptr_t)texture_handle.value, size);
				}
			}
			else {
				ImGui::Rect(size.x, size.y, 0xffFF00FF);
			}
			const bool is_hovered = ImGui::IsItemHovered();
			if (is_hovered && ImGui::IsMouseClicked(0) && m_editor.isGameMode()) captureMouse(true);
			m_pos = ImGui::GetItemRectMin();
			m_size = ImGui::GetItemRectSize();

			if (m_is_mouse_captured) {
				OS::clipCursor((int)m_pos.x, (int)m_pos.y, (int)m_size.x, (int)m_size.y);
			}

			processInputEvents();
			controlsGUI();
		}

	}
	if (m_is_mouse_captured && OS::getFocused() != ImGui::GetWindowViewport()->PlatformHandle) captureMouse(false);
	ImGui::End();
	ImGui::PopStyleVar();
	if (is_game_view_visible) onStatsGUI(view_pos);
}

} // namespace Lumix
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX グループ・QSPI I/O 制御
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/renesas.hpp"
#include "common/vect.h"

/// F_PCKx は速度パラメーター計算で必要で、設定が無いとエラーにします。
#if defined(SIG_RX24T)
#  error "qspi_io.hpp not support for RX24T"
#elif defined(SIG_RX64M) || defined(SIG_RX71M) || defined(SIG_RX65N)
#ifndef F_PCLKA
#  error "qspi_io.hpp requires F_PCLKA to be defined"
#else
#undef PCLK
#define PCLK F_PCLKA
#endif
#endif

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  QSPI 制御クラス
		@param[in]	QSPI	QSPI 定義クラス
		@param[in]	PSEL	ポート候補
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class QSPI, port_map::option PSEL = port_map::option::FIRST>
	class qspi_io {
	public:

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  データ、クロック位相タイプ型
					TYPE1(MODE0): CPOL:0 CPHA:0 @n
					TYPE2(MODE1): CPOL:0 CPHA:1 @n
					TYPE3(MODE2): CPOL:1 CPHA:0 @n
					TYPE4(MODE3): CPOL:1 CPHA:1
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class PHASE : uint8_t {
			TYPE1,  ///< タイプ１
			TYPE2,  ///< タイプ２
			TYPE3,  ///< タイプ３
			TYPE4,  ///< タイプ４ (SD カードアクセス）
		};

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  データ長型
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class DLEN : uint8_t {
			W8  = 0b0111,	///< 8 Bits
			W9  = 0b1000,	///< 9 Bits
			W10 = 0b1001,	///< 10 Bits
			W11 = 0b1010,	///< 11 Bits
			W12 = 0b1011,	///< 12 Bits
			W13 = 0b1100,	///< 13 Bits
			W14 = 0b1101,	///< 14 Bits
			W15 = 0b1110,	///< 15 Bits
			W16 = 0b1111,	///< 16 Bits
			W20 = 0b0000,	///< 20 Bits
			W24 = 0b0001,	///< 24 Bits
			W32 = 0b0011,	///< 32 Bits
		};

	private:

		uint8_t	level_;

		// 便宜上のスリープ
		void sleep_() { asm("nop"); }

		bool clock_div_(uint32_t speed, uint8_t& brdv, uint8_t& spbr) {
///			utils::format("PCLK: %d\n") % static_cast<uint32_t>(PCLK);
			uint32_t br = static_cast<uint32_t>(PCLK) / speed;
			uint8_t dv = 0;
			while(br > 512) {
				br >>= 1;
				++dv;
				if(dv > 3) {
					brdv = 3;
					spbr = 255;
					return false;
				}
			}
			brdv = dv;
			if(br & 1) {
				br >>= 1;
				++br;
			} else {
				br >>= 1;
			}
			if(br) --br;
			spbr = br;
			return true;
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		qspi_io() noexcept : level_(0) { }

		//-----------------------------------------------------------------//
		/*!
			@brief  通信速度を設定して、CSI を有効にする
			@param[in]	speed	通信速度
			@param[in]	ctype	クロック位相タイプ
			@param[in]	dlen	データ長設定
			@param[in]	level	割り込みレベル（１～２）、０の場合はポーリング
			@return エラー（速度設定範囲外）なら「false」
		*/
		//-----------------------------------------------------------------//
		bool start(uint32_t speed, PHASE ctype, DLEN dlen, uint8_t level = 0) noexcept
		{
			level_ = level;

			// デバイスを不許可
			QSPI::SPCR = 0x00;

			// ポートを有効にする
			port_map::turn(QSPI::get_peripheral(), true, PSEL);

			bool f = true;
			uint8_t brdv;
			uint8_t spbr;
			if(!clock_div_(speed, brdv, spbr)) {
				f = false;
			}

			power_cfg::turn(QSPI::get_peripheral());

			// 設定
		    QSPI::SPBR = spbr;
			QSPI::SPPCR = 0x00;	// Fixed idle value, disable loop-back
			QSPI::SPSCR = 0x00;	// disable sequence control
			QSPI::SPDCR = 0x20;	// SPLW=1 (long word access)
///			QSPI::SPCMD0 = RSPI::SPCMD0.LSBF.b() | RSPI::SPCMD0.BRDV.b(brdv) | RSPI::SPCMD0.SPB.b(0b0100);
			bool cpol = 0;
			bool cpha = 0;
			switch(ctype) {
			case PHASE::TYPE1:
				break;
			case PHASE::TYPE2:
				cpha = 1;
				break;
			case PHASE::TYPE3:
				cpol = 1;
				break;
			case PHASE::TYPE4:
				cpol = 1;
				cpha = 1;
				break;
			default:
				break;
			}
			QSPI::SPCMD0 = QSPI::SPCMD0.BRDV.b(brdv)
				| QSPI::SPCMD0.SPB.b(static_cast<uint8_t>(dlen))
				| QSPI::SPCMD0.CPOL.b(cpol) | QSPI::SPCMD0.CPHA.b(cpha);

			QSPI::SPCR.MSTR = 1;

			QSPI::SPCR.SPE = 1;

			return f;
		}

		//----------------------------------------------------------------//
		/*!
			@brief	リード・ライト
			@param[in]	data	書き込みデータ
			@return 読み出しデータ
		*/
		//----------------------------------------------------------------//
		uint8_t xchg(uint8_t data = 0xff) noexcept
		{
			QSPI::SPDR = static_cast<uint32_t>(data);
			while(QSPI::SPSR.SPRF() == 0) sleep_();
		    return QSPI::SPDR();
		}

		//----------------------------------------------------------------//
		/*!
			@brief	リード・ライト
			@param[in]	data	書き込みデータ
			@return 読み出しデータ
		*/
		//----------------------------------------------------------------//
		uint32_t xchg32(uint32_t data = 0) noexcept
		{
			QSPI::SPDR = static_cast<uint32_t>(data);
			while(QSPI::SPSR.SPRF() == 0) sleep_();
		    return QSPI::SPDR();
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  シリアル送信
			@param[in]	src	送信ソース
			@param[in]	cnt	送信サイズ
		*/
		//-----------------------------------------------------------------//
		void send(const uint8_t* src, uint16_t size) noexcept
		{
			auto end = src + size;
			while(src < end) {
				xchg(*src);
				++src;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  シリアル受信
			@param[out]	dst	受信先
			@param[in]	cnt	受信サイズ
		*/
		//-----------------------------------------------------------------//
		void recv(uint8_t* dst, uint16_t size) noexcept
		{
			auto end = dst + size;
			while(dst < end) {
				*dst = xchg();
				++dst;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  RSPIを無効にして、パワーダウンする
			@param[in]	power パワーダウンをしない場合「false」
		*/
		//-----------------------------------------------------------------//
		void destroy(bool power = true) noexcept
		{
			QSPI::SPCR = 0x00;
			port_map::turn(QSPI::get_peripheral(), false);
			if(power) power_cfg::turn(QSPI::get_peripheral(), false);
		}
	};
}
<commit_msg>update: cleanup<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	RX グループ・QSPI I/O 制御
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/renesas.hpp"
#include "common/vect.h"

/// F_PCKx は速度パラメーター計算で必要で、設定が無いとエラーにします。
#if defined(SIG_RX24T)
#  error "qspi_io.hpp not support for RX24T"
#elif defined(SIG_RX64M) || defined(SIG_RX71M) || defined(SIG_RX65N)
#ifndef F_PCLKB
#  error "qspi_io.hpp requires F_PCLKB to be defined"
#else
#undef PCLK
#define PCLK F_PCLKB
#endif
#endif

namespace device {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  QSPI 制御クラス
		@param[in]	QSPI	QSPI 定義クラス
		@param[in]	PSEL	ポート候補
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class QSPI, port_map::option PSEL = port_map::option::FIRST>
	class qspi_io {
	public:

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  データ、クロック位相タイプ型
					TYPE1(MODE0): CPOL:0 CPHA:0 @n
					TYPE2(MODE1): CPOL:0 CPHA:1 @n
					TYPE3(MODE2): CPOL:1 CPHA:0 @n
					TYPE4(MODE3): CPOL:1 CPHA:1
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class PHASE : uint8_t {
			TYPE1,  ///< タイプ１
			TYPE2,  ///< タイプ２
			TYPE3,  ///< タイプ３
			TYPE4,  ///< タイプ４ (SD カードアクセス）
		};

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  データ長型
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class DLEN : uint8_t {
			W8  = 0b0111,	///< 8 Bits
			W9  = 0b1000,	///< 9 Bits
			W10 = 0b1001,	///< 10 Bits
			W11 = 0b1010,	///< 11 Bits
			W12 = 0b1011,	///< 12 Bits
			W13 = 0b1100,	///< 13 Bits
			W14 = 0b1101,	///< 14 Bits
			W15 = 0b1110,	///< 15 Bits
			W16 = 0b1111,	///< 16 Bits
			W20 = 0b0000,	///< 20 Bits
			W24 = 0b0001,	///< 24 Bits
			W32 = 0b0011,	///< 32 Bits
		};

	private:

		uint8_t	level_;

		// 便宜上のスリープ
		void sleep_() { asm("nop"); }

		bool clock_div_(uint32_t speed, uint8_t& brdv, uint8_t& spbr) {
///			utils::format("PCLK: %d\n") % static_cast<uint32_t>(PCLK);
			uint32_t br = static_cast<uint32_t>(PCLK) / speed;
			uint8_t dv = 0;
			while(br > 512) {
				br >>= 1;
				++dv;
				if(dv > 3) {
					brdv = 3;
					spbr = 255;
					return false;
				}
			}
			brdv = dv;
			if(br & 1) {
				br >>= 1;
				++br;
			} else {
				br >>= 1;
			}
			if(br) --br;
			spbr = br;
			return true;
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
		*/
		//-----------------------------------------------------------------//
		qspi_io() noexcept : level_(0) { }

		//-----------------------------------------------------------------//
		/*!
			@brief  通信速度を設定して、CSI を有効にする
			@param[in]	speed	通信速度
			@param[in]	ctype	クロック位相タイプ
			@param[in]	dlen	データ長設定
			@param[in]	level	割り込みレベル（１～２）、０の場合はポーリング
			@return エラー（速度設定範囲外）なら「false」
		*/
		//-----------------------------------------------------------------//
		bool start(uint32_t speed, PHASE ctype, DLEN dlen, uint8_t level = 0) noexcept
		{
			level_ = level;

			// デバイスを不許可
			QSPI::SPCR = 0x00;

			// ポートを有効にする
			port_map::turn(QSPI::get_peripheral(), true, PSEL);

			bool f = true;
			uint8_t brdv;
			uint8_t spbr;
			if(!clock_div_(speed, brdv, spbr)) {
				f = false;
			}

			power_cfg::turn(QSPI::get_peripheral());

			// 設定
		    QSPI::SPBR = spbr;
			QSPI::SPPCR = 0x00;	// Fixed idle value, disable loop-back
			QSPI::SPSCR = 0x00;	// disable sequence control
			QSPI::SPDCR = 0x20;	// SPLW=1 (long word access)
///			QSPI::SPCMD0 = RSPI::SPCMD0.LSBF.b() | RSPI::SPCMD0.BRDV.b(brdv) | RSPI::SPCMD0.SPB.b(0b0100);
			bool cpol = 0;
			bool cpha = 0;
			switch(ctype) {
			case PHASE::TYPE1:
				break;
			case PHASE::TYPE2:
				cpha = 1;
				break;
			case PHASE::TYPE3:
				cpol = 1;
				break;
			case PHASE::TYPE4:
				cpol = 1;
				cpha = 1;
				break;
			default:
				break;
			}
			QSPI::SPCMD0 = QSPI::SPCMD0.BRDV.b(brdv)
				| QSPI::SPCMD0.SPB.b(static_cast<uint8_t>(dlen))
				| QSPI::SPCMD0.CPOL.b(cpol) | QSPI::SPCMD0.CPHA.b(cpha);

			QSPI::SPCR.MSTR = 1;

			QSPI::SPCR.SPE = 1;

			return f;
		}

		//----------------------------------------------------------------//
		/*!
			@brief	リード・ライト
			@param[in]	data	書き込みデータ
			@return 読み出しデータ
		*/
		//----------------------------------------------------------------//
		uint8_t xchg(uint8_t data = 0xff) noexcept
		{
			QSPI::SPDR = static_cast<uint32_t>(data);
			while(QSPI::SPSR.SPRF() == 0) sleep_();
		    return QSPI::SPDR();
		}

		//----------------------------------------------------------------//
		/*!
			@brief	リード・ライト
			@param[in]	data	書き込みデータ
			@return 読み出しデータ
		*/
		//----------------------------------------------------------------//
		uint32_t xchg32(uint32_t data = 0) noexcept
		{
			QSPI::SPDR = static_cast<uint32_t>(data);
			while(QSPI::SPSR.SPRF() == 0) sleep_();
		    return QSPI::SPDR();
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  シリアル送信
			@param[in]	src	送信ソース
			@param[in]	cnt	送信サイズ
		*/
		//-----------------------------------------------------------------//
		void send(const uint8_t* src, uint16_t size) noexcept
		{
			auto end = src + size;
			while(src < end) {
				xchg(*src);
				++src;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  シリアル受信
			@param[out]	dst	受信先
			@param[in]	cnt	受信サイズ
		*/
		//-----------------------------------------------------------------//
		void recv(uint8_t* dst, uint16_t size) noexcept
		{
			auto end = dst + size;
			while(dst < end) {
				*dst = xchg();
				++dst;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  RSPIを無効にして、パワーダウンする
			@param[in]	power パワーダウンをしない場合「false」
		*/
		//-----------------------------------------------------------------//
		void destroy(bool power = true) noexcept
		{
			QSPI::SPCR = 0x00;
			port_map::turn(QSPI::get_peripheral(), false);
			if(power) power_cfg::turn(QSPI::get_peripheral(), false);
		}
	};
}
<|endoftext|>