<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2006 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "FFMpegDecoder.h"

#include "Player.h"
#include "../base/Exception.h"
#include "../base/Logger.h"
#include "../base/ScopeTimer.h"

#include <iostream>
#include <sstream>
#include <unistd.h>

using namespace std;

namespace avg {

bool FFMpegDecoder::m_bInitialized = false;

FFMpegDecoder::FFMpegDecoder ()
    : m_pFormatContext(0),
      m_pVStream(0),
      m_pPacketData(0)
{
    initVideoSupport();
}

FFMpegDecoder::~FFMpegDecoder ()
{
    if (m_pFormatContext) {
        close();
    }
}

void avcodecError(const string & filename, int err)
{
    switch(err) {
        case AVERROR_NUMEXPECTED:
            AVG_TRACE(Logger::ERROR,
                    filename << ": Incorrect image filename syntax.");
            AVG_TRACE(Logger::ERROR,
                    "Use '%%d' to specify the image number:");
            AVG_TRACE(Logger::ERROR,
                    "  for img1.jpg, img2.jpg, ..., use 'img%%d.jpg';");
            AVG_TRACE(Logger::ERROR,
                    "  for img001.jpg, img002.jpg, ..., use 'img%%03d.jpg'.");
            break;
        case AVERROR_INVALIDDATA:
            AVG_TRACE(Logger::ERROR,
                    filename << ": Error while parsing header");
            break;
        case AVERROR_NOFMT:
            AVG_TRACE(Logger::ERROR,
                    filename << ": Unknown format");
            break;
        default:
            AVG_TRACE(Logger::ERROR,
                    filename << ": Error while opening file (Num:" << err << ")");
            break;
    }
    // TODO: Continue without video.
    exit(-1);
}

void dump_stream_info(AVFormatContext *s)
{
    cerr << "Stream info: " << endl;
    if (s->track != 0)
        fprintf(stderr, "  Track: %d\n", s->track);
    if (s->title[0] != '\0')
        fprintf(stderr, "  Title: %s\n", s->title);
    if (s->author[0] != '\0')
        fprintf(stderr, "  Author: %s\n", s->author);
    if (s->album[0] != '\0')
        fprintf(stderr, "  Album: %s\n", s->album);
    if (s->year != 0)
        fprintf(stderr, "  Year: %d\n", s->year);
    if (s->genre[0] != '\0')
        fprintf(stderr, "  Genre: %s\n", s->genre);
}

bool FFMpegDecoder::open (const std::string& sFilename,
        int* pWidth, int* pHeight)
{
    AVFormatParameters params;
    int err;
    m_sFilename = sFilename;

    AVG_TRACE(Logger::PROFILE, "Opening " << sFilename);
    memset(&params, 0, sizeof(params));
    params.image_format = 0;

    err = av_open_input_file(&m_pFormatContext, sFilename.c_str(),
            0, 0, &params);
    if (err < 0) {
        avcodecError(sFilename, err);
    }

    err = av_find_stream_info(m_pFormatContext);
    if (err < 0) {
        AVG_TRACE(Logger::ERROR,
                    sFilename << ": Could not find codec parameters.");
        return false;
    }

    av_read_play(m_pFormatContext);

    m_VStreamIndex = -1;
    for(int i = 0; i < m_pFormatContext->nb_streams; i++) {
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
        AVCodecContext *enc = &m_pFormatContext->streams[i]->codec;
#else
        AVCodecContext *enc = m_pFormatContext->streams[i]->codec;
#endif
        switch(enc->codec_type) {
/*
           case CODEC_TYPE_AUDIO:
               if (audio_index < 0 && !audio_disable)
               audio_index = i;
               break;
*/
            case CODEC_TYPE_VIDEO:
                if (m_VStreamIndex < 0)
                    m_VStreamIndex = i;
                break;
            default:
                break;
        }
    }
//    dump_format(m_pFormatContext, 0, m_sFilename.c_str(), 0);
//    dump_stream_info(m_pFormatContext);
    if (m_VStreamIndex < 0) {
        AVG_TRACE(Logger::ERROR,
                    sFilename << " does not contain any video streams.");
        return false;
    }
    AVCodecContext *enc;
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
    enc = &(m_pFormatContext->streams[m_VStreamIndex]->codec);
#else
    enc = m_pFormatContext->streams[m_VStreamIndex]->codec;
#endif
//    enc->debug = 0x0001; // see avcodec.h

    AVCodec * codec = avcodec_find_decoder(enc->codec_id);
    if (!codec ||
        avcodec_open(enc, codec) < 0)
    {
        AVG_TRACE(Logger::ERROR,
                    sFilename << ": could not open codec (?!).");
        return false;
    }
    m_pVStream = m_pFormatContext->streams[m_VStreamIndex];
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
    *pWidth =  m_pVStream->codec.width;
    *pHeight = m_pVStream->codec.height;
#else
    *pWidth =  m_pVStream->codec->width;
    *pHeight = m_pVStream->codec->height;
#endif
    m_bFirstPacket = true;
    m_PacketLenLeft = 0;
    m_bEOF = false;
    return true;
}

void FFMpegDecoder::close()
{
    AVG_TRACE(Logger::PROFILE, "Closing " << m_sFilename);
    AVCodecContext * enc;
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
    enc = &(m_pFormatContext->streams[m_VStreamIndex]->codec);
#else
    enc = m_pFormatContext->streams[m_VStreamIndex]->codec;
#endif
    if (!m_bFirstPacket) {
        av_free_packet(&m_Packet);
    }
    m_pPacketData = 0;
    avcodec_close(enc);
    m_pVStream = 0;
    av_close_input_file(m_pFormatContext);
    m_pFormatContext = 0;
}

void FFMpegDecoder::seek(int DestFrame, int CurFrame)
{
#if LIBAVFORMAT_BUILD <= 4616
    av_seek_frame(m_pFormatContext, m_VStreamIndex,
            int((double(DestFrame)*1000000*1000)/m_pVStream->r_frame_rate));
#else
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
    av_seek_frame(m_pFormatContext, m_VStreamIndex,
            int((double(DestFrame)*1000000*1000)/m_pVStream->r_frame_rate), 0);
#else
    double framerate = (m_pVStream->r_frame_rate.num)/m_pVStream->r_frame_rate.den;
    av_seek_frame(m_pFormatContext, m_VStreamIndex,
            int((double(DestFrame)*1000000*1000)/framerate), 0);
#endif
#endif
}

int FFMpegDecoder::getNumFrames()
{
    // This is broken for some videos, but the code here is correct.
    // So fix the videos or ffmpeg :-).
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
    return m_pVStream->r_frame_rate*(m_pVStream->duration/AV_TIME_BASE);
#else
    return (m_pVStream->r_frame_rate.num/m_pVStream->r_frame_rate.den)*(m_pVStream->duration/AV_TIME_BASE);
#endif
}

double FFMpegDecoder::getFPS()
{
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
    return m_pVStream->r_frame_rate;
#else
    return (m_pVStream->r_frame_rate.num/m_pVStream->r_frame_rate.den);
#endif
}

static ProfilingZone RenderToBmpProfilingZone("      FFMpeg: renderToBmp");
static ProfilingZone ImgConvertProfilingZone("        FFMpeg: img_convert");

bool FFMpegDecoder::renderToBmp(BitmapPtr pBmp)
{
    ScopeTimer Timer(RenderToBmpProfilingZone);
    AVFrame Frame;
    readFrame(Frame);
    if (!m_bEOF) {
        AVPicture DestPict;
        unsigned char * pDestBits = pBmp->getPixels();
        DestPict.data[0] = pDestBits;
        DestPict.data[1] = pDestBits+1;
        DestPict.data[2] = pDestBits+2;
        DestPict.data[3] = pDestBits+3;
        DestPict.linesize[0] = pBmp->getStride();
        DestPict.linesize[1] = pBmp->getStride();
        DestPict.linesize[2] = pBmp->getStride();
        DestPict.linesize[3] = pBmp->getStride();
        int DestFmt;
        switch(pBmp->getPixelFormat()) {
            case R8G8B8X8:
                DestFmt = PIX_FMT_RGBA32;
                break;
            case B8G8R8X8:
                // This isn't supported directly by FFMpeg.
                DestFmt = PIX_FMT_RGBA32;
                DestPict.data[1] = pDestBits+3;
                DestPict.data[3] = pDestBits+1;
                break;
            case R8G8B8:
                DestFmt = PIX_FMT_RGB24;
                break;
            case B8G8R8:
                DestFmt = PIX_FMT_BGR24;
                break;
            case YCbCr422:
                DestFmt = PIX_FMT_YUV422;
                break;
            default:
                AVG_TRACE(Logger::ERROR, "FFMpegDecoder: Dest format "
                        << pBmp->getPixelFormatString() << " not supported.");
                assert(false);
        }
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
        AVCodecContext *enc = &m_pVStream->codec;
#else
        AVCodecContext *enc = m_pVStream->codec;
#endif
        {
            ScopeTimer Timer(ImgConvertProfilingZone);
            img_convert(&DestPict, DestFmt,
                    (AVPicture*)&Frame, enc->pix_fmt,
                    enc->width, enc->height);
        }
    }
    return m_bEOF;
}

bool FFMpegDecoder::isYCbCrSupported()
{
    return true;
}

bool FFMpegDecoder::canRenderToBuffer(int BPP)
{
//TODO: This is a bug: We should enable direct rendering if DFB is being
//      used and not just compiled in!
#ifdef AVG_ENABLE_DFB
    return (BPP == 24);
#else
    return false;
#endif
}

void FFMpegDecoder::initVideoSupport()
{
    if (!m_bInitialized) {
        av_register_all();
        m_bInitialized = true;
        // Avoid libavcodec console spam - turn this up again when libavcodec
        // doesn't spam anymore :-).
//        av_log_set_level(AV_LOG_DEBUG);
        av_log_set_level(AV_LOG_QUIET);
    }
}

void FFMpegDecoder::readFrame(AVFrame& Frame)
{
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
        AVCodecContext *enc = &m_pVStream->codec;
#else
        AVCodecContext *enc = m_pVStream->codec;
#endif
    if (enc->codec_id == CODEC_ID_RAWVIDEO) {
        AVPacket Packet;
        m_bEOF = getNextVideoPacket(Packet);
        if (m_bEOF) {
            return ;
        }
        avpicture_fill((AVPicture*)&Frame, Packet.data,
                enc->pix_fmt,
                enc->width, enc->height);
        av_free_packet(&Packet);
    } else {
        int gotPicture = 0;
        while (!gotPicture) {
            if (m_PacketLenLeft <= 0) {
                if (!m_bFirstPacket) {
                    av_free_packet(&m_Packet);
                }
                m_bFirstPacket = false;
                m_bEOF = getNextVideoPacket(m_Packet);
                if (m_bEOF) {
                    return ;
                }
                m_PacketLenLeft = m_Packet.size;
                m_pPacketData = m_Packet.data;
            }
            int Len1 = avcodec_decode_video(enc, &Frame,
                    &gotPicture, m_pPacketData, m_PacketLenLeft);
            if (Len1 < 0) {
                AVG_TRACE(Logger::WARNING, "Error decoding " <<
                        m_sFilename);
                // TODO: simulate eof.
            }
            m_pPacketData += Len1;
            m_PacketLenLeft -= Len1;
        }
/*
        cerr << "coded_picture_number: " << Frame.coded_picture_number <<
                ", display_picture_number: " << Frame.display_picture_number <<
                ", pts: " << Frame.pts << endl;

        cerr << "key_frame: " << Frame.key_frame <<
               ", pict_type: " << Frame.pict_type << endl;
        AVFrac spts = m_pVStream->pts;
        cerr << "Stream.pts: " << spts.val + double(spts.num)/spts.den << endl;
*/
    }
}

bool FFMpegDecoder::getNextVideoPacket(AVPacket & Packet) {
    AVPacket CurPacket;
    int err = av_read_frame(m_pFormatContext, &CurPacket);
    if (err < 0) {
        return true;
    }
    while (CurPacket.stream_index != m_VStreamIndex) {
        av_free_packet(&CurPacket);
        int err = av_read_frame(m_pFormatContext, &CurPacket);
        if (err < 0) {
            return true;
        }
    }
    Packet = CurPacket;
/*    if (Packet.pts != AV_NOPTS_VALUE) {
        cerr << "Packet.pts: " <<
            double(Packet.pts)*m_pFormatContext->pts_num/m_pFormatContext->pts_den << endl;
    }
*/
    return false;
}

}

<commit_msg>Fixed seek with newer ffmpeg.<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2006 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "FFMpegDecoder.h"

#include "Player.h"
#include "../base/Exception.h"
#include "../base/Logger.h"
#include "../base/ScopeTimer.h"

#include <iostream>
#include <sstream>
#include <unistd.h>

using namespace std;

namespace avg {

bool FFMpegDecoder::m_bInitialized = false;

FFMpegDecoder::FFMpegDecoder ()
    : m_pFormatContext(0),
      m_pVStream(0),
      m_pPacketData(0)
{
    initVideoSupport();
}

FFMpegDecoder::~FFMpegDecoder ()
{
    if (m_pFormatContext) {
        close();
    }
}

void avcodecError(const string & filename, int err)
{
    switch(err) {
        case AVERROR_NUMEXPECTED:
            AVG_TRACE(Logger::ERROR,
                    filename << ": Incorrect image filename syntax.");
            AVG_TRACE(Logger::ERROR,
                    "Use '%%d' to specify the image number:");
            AVG_TRACE(Logger::ERROR,
                    "  for img1.jpg, img2.jpg, ..., use 'img%%d.jpg';");
            AVG_TRACE(Logger::ERROR,
                    "  for img001.jpg, img002.jpg, ..., use 'img%%03d.jpg'.");
            break;
        case AVERROR_INVALIDDATA:
            AVG_TRACE(Logger::ERROR,
                    filename << ": Error while parsing header");
            break;
        case AVERROR_NOFMT:
            AVG_TRACE(Logger::ERROR,
                    filename << ": Unknown format");
            break;
        default:
            AVG_TRACE(Logger::ERROR,
                    filename << ": Error while opening file (Num:" << err << ")");
            break;
    }
    // TODO: Continue without video.
    exit(-1);
}

void dump_stream_info(AVFormatContext *s)
{
    cerr << "Stream info: " << endl;
    if (s->track != 0)
        fprintf(stderr, "  Track: %d\n", s->track);
    if (s->title[0] != '\0')
        fprintf(stderr, "  Title: %s\n", s->title);
    if (s->author[0] != '\0')
        fprintf(stderr, "  Author: %s\n", s->author);
    if (s->album[0] != '\0')
        fprintf(stderr, "  Album: %s\n", s->album);
    if (s->year != 0)
        fprintf(stderr, "  Year: %d\n", s->year);
    if (s->genre[0] != '\0')
        fprintf(stderr, "  Genre: %s\n", s->genre);
}

bool FFMpegDecoder::open (const std::string& sFilename,
        int* pWidth, int* pHeight)
{
    AVFormatParameters params;
    int err;
    m_sFilename = sFilename;

    AVG_TRACE(Logger::PROFILE, "Opening " << sFilename);
    memset(&params, 0, sizeof(params));
    params.image_format = 0;

    err = av_open_input_file(&m_pFormatContext, sFilename.c_str(),
            0, 0, &params);
    if (err < 0) {
        avcodecError(sFilename, err);
    }

    err = av_find_stream_info(m_pFormatContext);
    if (err < 0) {
        AVG_TRACE(Logger::ERROR,
                    sFilename << ": Could not find codec parameters.");
        return false;
    }

    av_read_play(m_pFormatContext);

    m_VStreamIndex = -1;
    for(int i = 0; i < m_pFormatContext->nb_streams; i++) {
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
        AVCodecContext *enc = &m_pFormatContext->streams[i]->codec;
#else
        AVCodecContext *enc = m_pFormatContext->streams[i]->codec;
#endif
        switch(enc->codec_type) {
/*
           case CODEC_TYPE_AUDIO:
               if (audio_index < 0 && !audio_disable)
               audio_index = i;
               break;
*/
            case CODEC_TYPE_VIDEO:
                if (m_VStreamIndex < 0)
                    m_VStreamIndex = i;
                break;
            default:
                break;
        }
    }
//    dump_format(m_pFormatContext, 0, m_sFilename.c_str(), 0);
//    dump_stream_info(m_pFormatContext);
    if (m_VStreamIndex < 0) {
        AVG_TRACE(Logger::ERROR,
                    sFilename << " does not contain any video streams.");
        return false;
    }
    AVCodecContext *enc;
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
    enc = &(m_pFormatContext->streams[m_VStreamIndex]->codec);
#else
    enc = m_pFormatContext->streams[m_VStreamIndex]->codec;
#endif
//    enc->debug = 0x0001; // see avcodec.h

    AVCodec * codec = avcodec_find_decoder(enc->codec_id);
    if (!codec ||
        avcodec_open(enc, codec) < 0)
    {
        AVG_TRACE(Logger::ERROR,
                    sFilename << ": could not open codec (?!).");
        return false;
    }
    m_pVStream = m_pFormatContext->streams[m_VStreamIndex];
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
    *pWidth =  m_pVStream->codec.width;
    *pHeight = m_pVStream->codec.height;
#else
    *pWidth =  m_pVStream->codec->width;
    *pHeight = m_pVStream->codec->height;
#endif
    m_bFirstPacket = true;
    m_PacketLenLeft = 0;
    m_bEOF = false;
    return true;
}

void FFMpegDecoder::close()
{
    AVG_TRACE(Logger::PROFILE, "Closing " << m_sFilename);
    AVCodecContext * enc;
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
    enc = &(m_pFormatContext->streams[m_VStreamIndex]->codec);
#else
    enc = m_pFormatContext->streams[m_VStreamIndex]->codec;
#endif
    if (!m_bFirstPacket) {
        av_free_packet(&m_Packet);
    }
    m_pPacketData = 0;
    avcodec_close(enc);
    m_pVStream = 0;
    av_close_input_file(m_pFormatContext);
    m_pFormatContext = 0;
}

void FFMpegDecoder::seek(int DestFrame, int CurFrame)
{
#if LIBAVFORMAT_BUILD <= 4616
    av_seek_frame(m_pFormatContext, m_VStreamIndex,
            int((double(DestFrame)*1000000*1000)/m_pVStream->r_frame_rate));
#else
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
    av_seek_frame(m_pFormatContext, m_VStreamIndex,
            int((double(DestFrame)*1000000*1000)/m_pVStream->r_frame_rate), 0);
#else
    double framerate = (m_pVStream->r_frame_rate.num)/m_pVStream->r_frame_rate.den;

    av_seek_frame(m_pFormatContext, m_VStreamIndex,
            int((double(DestFrame)*AV_TIME_BASE)/framerate), 0);
#endif
#endif
}

int FFMpegDecoder::getNumFrames()
{
    // This is broken for some videos, but the code here is correct.
    // So fix the videos or ffmpeg :-).
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
    return m_pVStream->r_frame_rate*(m_pVStream->duration/AV_TIME_BASE);
#else
    return (m_pVStream->r_frame_rate.num/m_pVStream->r_frame_rate.den)*(m_pVStream->duration/AV_TIME_BASE);
#endif
}

double FFMpegDecoder::getFPS()
{
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
    return m_pVStream->r_frame_rate;
#else
    return (m_pVStream->r_frame_rate.num/m_pVStream->r_frame_rate.den);
#endif
}

static ProfilingZone RenderToBmpProfilingZone("      FFMpeg: renderToBmp");
static ProfilingZone ImgConvertProfilingZone("        FFMpeg: img_convert");

bool FFMpegDecoder::renderToBmp(BitmapPtr pBmp)
{
    ScopeTimer Timer(RenderToBmpProfilingZone);
    AVFrame Frame;
    readFrame(Frame);
    if (!m_bEOF) {
        AVPicture DestPict;
        unsigned char * pDestBits = pBmp->getPixels();
        DestPict.data[0] = pDestBits;
        DestPict.data[1] = pDestBits+1;
        DestPict.data[2] = pDestBits+2;
        DestPict.data[3] = pDestBits+3;
        DestPict.linesize[0] = pBmp->getStride();
        DestPict.linesize[1] = pBmp->getStride();
        DestPict.linesize[2] = pBmp->getStride();
        DestPict.linesize[3] = pBmp->getStride();
        int DestFmt;
        switch(pBmp->getPixelFormat()) {
            case R8G8B8X8:
                DestFmt = PIX_FMT_RGBA32;
                break;
            case B8G8R8X8:
                // This isn't supported directly by FFMpeg.
                DestFmt = PIX_FMT_RGBA32;
                DestPict.data[1] = pDestBits+3;
                DestPict.data[3] = pDestBits+1;
                break;
            case R8G8B8:
                DestFmt = PIX_FMT_RGB24;
                break;
            case B8G8R8:
                DestFmt = PIX_FMT_BGR24;
                break;
            case YCbCr422:
                DestFmt = PIX_FMT_YUV422;
                break;
            default:
                AVG_TRACE(Logger::ERROR, "FFMpegDecoder: Dest format "
                        << pBmp->getPixelFormatString() << " not supported.");
                assert(false);
        }
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
        AVCodecContext *enc = &m_pVStream->codec;
#else
        AVCodecContext *enc = m_pVStream->codec;
#endif
        {
            ScopeTimer Timer(ImgConvertProfilingZone);
            img_convert(&DestPict, DestFmt,
                    (AVPicture*)&Frame, enc->pix_fmt,
                    enc->width, enc->height);
        }
    }
    return m_bEOF;
}

bool FFMpegDecoder::isYCbCrSupported()
{
    return true;
}

bool FFMpegDecoder::canRenderToBuffer(int BPP)
{
//TODO: This is a bug: We should enable direct rendering if DFB is being
//      used and not just compiled in!
#ifdef AVG_ENABLE_DFB
    return (BPP == 24);
#else
    return false;
#endif
}

void FFMpegDecoder::initVideoSupport()
{
    if (!m_bInitialized) {
        av_register_all();
        m_bInitialized = true;
        // Avoid libavcodec console spam - turn this up again when libavcodec
        // doesn't spam anymore :-).
//        av_log_set_level(AV_LOG_DEBUG);
        av_log_set_level(AV_LOG_QUIET);
    }
}

void FFMpegDecoder::readFrame(AVFrame& Frame)
{
#if LIBAVFORMAT_BUILD < ((49<<16)+(0<<8)+0)
        AVCodecContext *enc = &m_pVStream->codec;
#else
        AVCodecContext *enc = m_pVStream->codec;
#endif
    if (enc->codec_id == CODEC_ID_RAWVIDEO) {
        AVPacket Packet;
        m_bEOF = getNextVideoPacket(Packet);
        if (m_bEOF) {
            return ;
        }
        avpicture_fill((AVPicture*)&Frame, Packet.data,
                enc->pix_fmt,
                enc->width, enc->height);
        av_free_packet(&Packet);
    } else {
        int gotPicture = 0;
        while (!gotPicture) {
            if (m_PacketLenLeft <= 0) {
                if (!m_bFirstPacket) {
                    av_free_packet(&m_Packet);
                }
                m_bFirstPacket = false;
                m_bEOF = getNextVideoPacket(m_Packet);
                if (m_bEOF) {
                    return ;
                }
                m_PacketLenLeft = m_Packet.size;
                m_pPacketData = m_Packet.data;
            }
            int Len1 = avcodec_decode_video(enc, &Frame,
                    &gotPicture, m_pPacketData, m_PacketLenLeft);
            if (Len1 < 0) {
                AVG_TRACE(Logger::WARNING, "Error decoding " <<
                        m_sFilename);
                // TODO: simulate eof.
            }
            m_pPacketData += Len1;
            m_PacketLenLeft -= Len1;
        }
/*
        cerr << "coded_picture_number: " << Frame.coded_picture_number <<
                ", display_picture_number: " << Frame.display_picture_number <<
                ", pts: " << Frame.pts << endl;

        cerr << "key_frame: " << Frame.key_frame <<
               ", pict_type: " << Frame.pict_type << endl;
        AVFrac spts = m_pVStream->pts;
        cerr << "Stream.pts: " << spts.val + double(spts.num)/spts.den << endl;
*/
    }
}

bool FFMpegDecoder::getNextVideoPacket(AVPacket & Packet) {
    AVPacket CurPacket;
    int err = av_read_frame(m_pFormatContext, &CurPacket);
    if (err < 0) {
        return true;
    }
    while (CurPacket.stream_index != m_VStreamIndex) {
        av_free_packet(&CurPacket);
        int err = av_read_frame(m_pFormatContext, &CurPacket);
        if (err < 0) {
            return true;
        }
    }
    Packet = CurPacket;
/*    if (Packet.pts != AV_NOPTS_VALUE) {
        cerr << "Packet.pts: " <<
            double(Packet.pts)*m_pFormatContext->pts_num/m_pFormatContext->pts_den << endl;
    }
*/
    return false;
}

}

<|endoftext|>


<commit_before>/*******************************************************************************

 Module:       JSBSim.cpp
 Author:       Jon S. Berndt
 Date started: 08/17/99
 Purpose:      Standalone version of JSBSim.
 Called by:    The USER.

 ------------- Copyright (C) 1999  Jon S. Berndt (jsb@hal-pc.org) -------------

 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
 Foundation; either version 2 of the License, or (at your option) any later
 version.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 details.

 You should have received a copy of the GNU General Public License along with
 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 Place - Suite 330, Boston, MA  02111-1307, USA.

 Further information about the GNU General Public License can also be found on
 the world wide web at http://www.gnu.org.

FUNCTIONAL DESCRIPTION
--------------------------------------------------------------------------------

This class Handles calling JSBSim standalone. It is set up for compilation under
Borland C+Builder or other compiler.

HISTORY
--------------------------------------------------------------------------------
08/17/99   JSB   Created

********************************************************************************
INCLUDES
*******************************************************************************/

#if __BCPLUSPLUS__  >= 0x0540   // If compiling under Borland C++Builder
#pragma hdrstop
#include <condefs.h>
USEUNIT("FGUtility.cpp");
USEUNIT("FGAtmosphere.cpp");
USEUNIT("FGAuxiliary.cpp");
USEUNIT("FGCoefficient.cpp");
USEUNIT("FGConfigFile.cpp");
USEUNIT("FGControls.cpp");
USEUNIT("FGEngine.cpp");
USEUNIT("FGFCS.cpp");
USEUNIT("FGFDMExec.cpp");
USEUNIT("FGfdmSocket.cpp");
USEUNIT("FGInitialCondition.cpp");
USEUNIT("FGLGear.cpp");
USEUNIT("FGMatrix.cpp");
USEUNIT("FGModel.cpp");
USEUNIT("FGOutput.cpp");
USEUNIT("FGPosition.cpp");
USEUNIT("FGRotation.cpp");
USEUNIT("FGState.cpp");
USEUNIT("FGTank.cpp");
USEUNIT("FGTranslation.cpp");
USEUNIT("FGAircraft.cpp");
USERES("JSBSim.res");
//---------------------------------------------------------------------------
#pragma argsused
#endif

#include "FGFDMExec.h"
#include "FGRotation.h"
#include "FGAtmosphere.h"
#include "FGState.h"
#include "FGFCS.h"
#include "FGAircraft.h"
#include "FGTranslation.h"
#include "FGPosition.h"
#include "FGAuxiliary.h"
#include "FGOutput.h"

#ifdef FGFS
#include <Include/compiler.h>
#include STL_IOSTREAM
#  ifdef FG_HAVE_STD_INCLUDES
#    include <ctime>
#  else
#    include <time.h>
#  endif
#else
#include <iostream>
#include <ctime>
#endif

int main(int argc, char** argv)
{
  FGFDMExec* FDMExec;

  if (argc != 3) {
    cout << endl
         << "  You must enter the name of a registered aircraft and reset point:"
         << endl << endl << "  FDM <aircraft name> <reset file>" << endl;
    exit(0);
  }

  FDMExec = new FGFDMExec();

  FDMExec->GetAircraft()->LoadAircraft("aircraft", "engine", string(argv[1]));
  FDMExec->GetState()->Reset("aircraft", string(argv[2]));

  while (FDMExec->GetState()->Getsim_time() <= 25.0)
  {
    //
    // Fake an elevator kick here after 5 seconds
    //

    if (FDMExec->GetState()->Getsim_time() > 5.0 &&
        FDMExec->GetState()->Getsim_time() < 6.0)
    {
      FDMExec->GetFCS()->SetDe(0.05);
    } else {
      FDMExec->GetFCS()->SetDe(0.00);
    }

    FDMExec->Run();
  }

  delete FDMExec;

  return 0;
}

<commit_msg>Replace call to Reset with call to Initialize<commit_after>/*******************************************************************************

 Module:       JSBSim.cpp
 Author:       Jon S. Berndt
 Date started: 08/17/99
 Purpose:      Standalone version of JSBSim.
 Called by:    The USER.

 ------------- Copyright (C) 1999  Jon S. Berndt (jsb@hal-pc.org) -------------

 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
 Foundation; either version 2 of the License, or (at your option) any later
 version.

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 details.

 You should have received a copy of the GNU General Public License along with
 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 Place - Suite 330, Boston, MA  02111-1307, USA.

 Further information about the GNU General Public License can also be found on
 the world wide web at http://www.gnu.org.

FUNCTIONAL DESCRIPTION
--------------------------------------------------------------------------------

This class Handles calling JSBSim standalone. It is set up for compilation under
Borland C+Builder or other compiler.

HISTORY
--------------------------------------------------------------------------------
08/17/99   JSB   Created

********************************************************************************
INCLUDES
*******************************************************************************/

#if __BCPLUSPLUS__  >= 0x0540   // If compiling under Borland C++Builder
#pragma hdrstop
#include <condefs.h>
USEUNIT("FGUtility.cpp");
USEUNIT("FGAtmosphere.cpp");
USEUNIT("FGAuxiliary.cpp");
USEUNIT("FGCoefficient.cpp");
USEUNIT("FGConfigFile.cpp");
USEUNIT("FGControls.cpp");
USEUNIT("FGEngine.cpp");
USEUNIT("FGFCS.cpp");
USEUNIT("FGFDMExec.cpp");
USEUNIT("FGfdmSocket.cpp");
USEUNIT("FGInitialCondition.cpp");
USEUNIT("FGLGear.cpp");
USEUNIT("FGMatrix.cpp");
USEUNIT("FGModel.cpp");
USEUNIT("FGOutput.cpp");
USEUNIT("FGPosition.cpp");
USEUNIT("FGRotation.cpp");
USEUNIT("FGState.cpp");
USEUNIT("FGTank.cpp");
USEUNIT("FGTranslation.cpp");
USEUNIT("FGAircraft.cpp");
USERES("JSBSim.res");
//---------------------------------------------------------------------------
#pragma argsused
#endif

#include "FGFDMExec.h"
#include "FGRotation.h"
#include "FGAtmosphere.h"
#include "FGState.h"
#include "FGFCS.h"
#include "FGAircraft.h"
#include "FGTranslation.h"
#include "FGPosition.h"
#include "FGAuxiliary.h"
#include "FGOutput.h"

#ifdef FGFS
#include <Include/compiler.h>
#include STL_IOSTREAM
#  ifdef FG_HAVE_STD_INCLUDES
#    include <ctime>
#  else
#    include <time.h>
#  endif
#else
#include <iostream>
#include <ctime>
#endif

int main(int argc, char** argv)
{
  FGFDMExec* FDMExec;

  if (argc != 3) {
    cout << endl
         << "  You must enter the name of a registered aircraft and reset point:"
         << endl << endl << "  FDM <aircraft name> <reset file>" << endl;
    exit(0);
  }

  FDMExec = new FGFDMExec();

  FDMExec->GetAircraft()->LoadAircraft("aircraft", "engine", string(argv[1]));
  //FDMExec->GetState()->Reset("aircraft", string(argv[2]));

  FDMExec->GetState()->Initialize(2000,0,0,0,0,0,0.5,0.5,40000);

  while (FDMExec->GetState()->Getsim_time() <= 5.0)
  {
    //
    // Fake an elevator kick here after 5 seconds
    //

    if (FDMExec->GetState()->Getsim_time() > 5.0 &&
        FDMExec->GetState()->Getsim_time() < 6.0)
    {
      FDMExec->GetFCS()->SetDe(0.05);
    } else {
      FDMExec->GetFCS()->SetDe(0.00);
    }

    FDMExec->Run();
  }

  delete FDMExec;

  return 0;
}

<|endoftext|>


<commit_before>#include "instanciate.h"
#include "details/context/isolate.h"
#include <memory>
#include "details/reporting/report.h"
#include "details/atom/func-overload-match.h"
#include "details/reporting/message.h"
#include "details/utils/origin.h"
#include "libnany-traces.h"

using namespace Yuni;

namespace Nany
{
namespace Pass
{
namespace Instanciate
{

	ProgramBuilder::ProgramBuilder(Logs::Report report, ClassdefTableView& cdeftable, const IntrinsicTable& intrinsics,
		IR::Program& out, IR::Program& program)
		: cdeftable(cdeftable)
		, intrinsics(intrinsics)
		, out(out)
		, currentProgram(program)
		, overloadMatch(report, cdeftable)
		, report(report)
	{
		// reduce memory allocations
		atomStack.reserve(4); // arbitrary
		lastPushedNamedParameters.reserve(32); // arbitrary
		lastPushedIndexedParameters.reserve(32);
		multipleResults.reserve(8); // arbitrary value
	}

	ProgramBuilder::~ProgramBuilder()
	{
		if (Config::Traces::printClassdefTable)
			printClassdefTable();
	}

	void ProgramBuilder::printClassdefTable()
	{
		while (not atomStack.empty())
		{
			printClassdefTable(report.subgroup(), atomStack.back());
			atomStack.pop_back();
		}
	}

	void ProgramBuilder::releaseScopedVariables(int scope, bool forget)
	{
		if (unlikely(atomStack.empty()))
			return;
		if (not forget and (not canGenerateCode()))
			return;

		auto& frame = atomStack.back();

		// unref in the reverse order
		auto i = static_cast<uint32_t>(frame.lvids.size());

		if (canGenerateCode())
		{
			while (i-- != 0)
			{
				auto& clcvr = frame.lvids[i];
				if (not (clcvr.scope >= scope))
					continue;

				if (clcvr.autorelease)
				{
					//if (not clcvr.userDefinedName.empty())
					//	out.emitComment(String{"unref var "} << clcvr.userDefinedName << " -> %" << i);
					tryUnrefObject(i);
				}

				// forget this variable!
				if (forget)
				{
					if (not clcvr.userDefinedName.empty() and clcvr.warning.unused)
					{
						if (unlikely(not clcvr.hasBeenUsed) and (clcvr.userDefinedName != "self"))
							complainUnusedVariable(frame, i);
					}

					clcvr.userDefinedName.clear();
					clcvr.scope = -1;
				}
			}
		}
		else
		{
			assert(forget == true);
			while (i-- != 0) // just invalidate everything
			{
				auto& clcvr = frame.lvids[i];
				if (clcvr.scope >= scope)
				{
					clcvr.userDefinedName.clear();
					clcvr.scope = -1;
				}
			}
		}
	}

	uint32_t ProgramBuilder::createLocalVariables(uint32_t count)
	{
		assert(lastOpcodeStacksizeOffset != (uint32_t) -1);
		assert(not atomStack.empty());
		assert(count > 0);

		auto& operands = out.at<IR::ISA::Op::stacksize>(lastOpcodeStacksizeOffset);
		uint32_t startOffset = operands.add;
		operands.add += count;

		auto& frame = atomStack.back();
		frame.resizeRegisterCount(operands.add, cdeftable);

		if (canGenerateCode())
		{
			for (uint32_t i = 0; i != count; ++i)
			{
				auto& lvidinfo = frame.lvids[startOffset + i];
				lvidinfo.scope = frame.scope;
				lvidinfo.offsetDeclOut = out.opcodeCount();
				out.emitStackalloc(startOffset + i, nyt_any);
			}
		}
		else
		{
			for (uint32_t i = 0; i != count; ++i)
				frame.lvids[startOffset + i].scope = frame.scope;
		}

		return startOffset;
	}

	void ProgramBuilder::printClassdefTable(Logs::Report trace, const AtomStackFrame& frame) const
	{
		auto entry = trace.trace();

		entry.message.prefix << cdeftable.keyword(frame.atom) << ' ';
		frame.atom.appendCaption(entry.message.prefix, cdeftable);
		entry << " - type matrix, after instanciation - atom " << frame.atom.atomid;

		for (uint i = 0; i != frame.localVariablesCount(); ++i)
		{
			auto clid = CLID{frame.atomid, i};
			auto entry = trace.trace();

			if (cdeftable.hasClassdef(clid) or cdeftable.hasSubstitute(clid))
			{
				cdeftable.printClassdef(entry.message.message, clid, cdeftable.classdef(clid));
				entry.message.message.trimRight();

				if (cdeftable.hasSubstitute(clid))
					entry << " (local replacement)";

				if (frame.lvids[i].isConstexpr)
					entry << " (constexpr)";
			}
			else
			{
				entry << "    " << clid << ": !!INVALID CLID";
			}
		}
	}

	bool ProgramBuilder::readAndInstanciate(uint32_t offset)
	{
		currentProgram.each(*this, offset);
		return success;
	}

} // namespace Instanciate
} // namespace Pass
} // namespace Nany

namespace Nany
{

	bool Isolate::instanciate(Logs::Report report, const AnyString& entrypoint)
	{
		// lock the isolate
		MutexLocker locker{mutex};

		// try to find the entrypoint
		Atom* entrypointAtom = nullptr;
		{
			bool canContinue = true;
			classdefTable.atoms.root.eachChild(entrypoint, [&](Atom& child) -> bool
			{
				if (entrypointAtom != nullptr)
				{
					canContinue = false;
					report.error() << "failed to instanciate '" << entrypoint << "': multiple entry points found";
					return false;
				}
				entrypointAtom = &child;
				return true;
			});

			if (not canContinue)
				return false;
		}

		if (unlikely(nullptr == entrypointAtom))
		{
			report.ICE() << "failed to instanciate '" << entrypoint << "()': function not found";
			return false;
		}

		if (unlikely(entrypointAtom->type != Atom::Type::funcdef))
		{
			report.ICE() << "failed to instanciate '" << entrypoint << "': the atom is not a function";
			return false;
		}

		// parameters for the signature
		decltype(FuncOverloadMatch::result.params)  params;
		Logs::Message::Ptr newReport;

		ClassdefTableView cdeftblView{classdefTable};

		Pass::Instanciate::InstanciateData info{newReport, *entrypointAtom, cdeftblView, intrinsics, params};
		auto* program = Pass::Instanciate::InstanciateAtom(info);
		report.appendEntry(newReport);
		return (nullptr != program);
	}

} // namespace Nany
<commit_msg>minor optimization for creating local variables<commit_after>#include "instanciate.h"
#include "details/context/isolate.h"
#include <memory>
#include "details/reporting/report.h"
#include "details/atom/func-overload-match.h"
#include "details/reporting/message.h"
#include "details/utils/origin.h"
#include "libnany-traces.h"

using namespace Yuni;

namespace Nany
{
namespace Pass
{
namespace Instanciate
{

	ProgramBuilder::ProgramBuilder(Logs::Report report, ClassdefTableView& cdeftable, const IntrinsicTable& intrinsics,
		IR::Program& out, IR::Program& program)
		: cdeftable(cdeftable)
		, intrinsics(intrinsics)
		, out(out)
		, currentProgram(program)
		, overloadMatch(report, cdeftable)
		, report(report)
	{
		// reduce memory allocations
		atomStack.reserve(4); // arbitrary
		lastPushedNamedParameters.reserve(32); // arbitrary
		lastPushedIndexedParameters.reserve(32);
		multipleResults.reserve(8); // arbitrary value
	}

	ProgramBuilder::~ProgramBuilder()
	{
		if (Config::Traces::printClassdefTable)
			printClassdefTable();
	}

	void ProgramBuilder::printClassdefTable()
	{
		while (not atomStack.empty())
		{
			printClassdefTable(report.subgroup(), atomStack.back());
			atomStack.pop_back();
		}
	}

	void ProgramBuilder::releaseScopedVariables(int scope, bool forget)
	{
		if (unlikely(atomStack.empty()))
			return;
		if (not forget and (not canGenerateCode()))
			return;

		auto& frame = atomStack.back();

		// unref in the reverse order
		auto i = static_cast<uint32_t>(frame.lvids.size());

		if (canGenerateCode())
		{
			while (i-- != 0)
			{
				auto& clcvr = frame.lvids[i];
				if (not (clcvr.scope >= scope))
					continue;

				if (clcvr.autorelease)
				{
					//if (not clcvr.userDefinedName.empty())
					//	out.emitComment(String{"unref var "} << clcvr.userDefinedName << " -> %" << i);
					tryUnrefObject(i);
				}

				// forget this variable!
				if (forget)
				{
					if (not clcvr.userDefinedName.empty() and clcvr.warning.unused)
					{
						if (unlikely(not clcvr.hasBeenUsed) and (clcvr.userDefinedName != "self"))
							complainUnusedVariable(frame, i);
					}

					clcvr.userDefinedName.clear();
					clcvr.scope = -1;
				}
			}
		}
		else
		{
			assert(forget == true);
			while (i-- != 0) // just invalidate everything
			{
				auto& clcvr = frame.lvids[i];
				if (clcvr.scope >= scope)
				{
					clcvr.userDefinedName.clear();
					clcvr.scope = -1;
				}
			}
		}
	}

	uint32_t ProgramBuilder::createLocalVariables(uint32_t count)
	{
		assert(lastOpcodeStacksizeOffset != (uint32_t) -1);
		assert(not atomStack.empty());
		assert(count > 0);

		auto& operands = out.at<IR::ISA::Op::stacksize>(lastOpcodeStacksizeOffset);
		uint32_t startOffset = operands.add;
		auto& frame = atomStack.back();

		if (count == 1)
		{
			frame.resizeRegisterCount((++operands.add), cdeftable);

			if (canGenerateCode())
			{
				auto& lvidinfo = frame.lvids[startOffset];
				lvidinfo.scope = frame.scope;
				lvidinfo.offsetDeclOut = out.opcodeCount();
				out.emitStackalloc(startOffset, nyt_any);
			}
			else
				frame.lvids[startOffset].scope = frame.scope;
		}
		else
		{
			operands.add += count;
			frame.resizeRegisterCount(operands.add, cdeftable);

			if (canGenerateCode())
			{
				for (uint32_t i = 0; i != count; ++i)
				{
					auto& lvidinfo = frame.lvids[startOffset + i];
					lvidinfo.scope = frame.scope;
					lvidinfo.offsetDeclOut = out.opcodeCount();
					out.emitStackalloc(startOffset + i, nyt_any);
				}
			}
			else
			{
				for (uint32_t i = 0; i != count; ++i)
					frame.lvids[startOffset + i].scope = frame.scope;
			}
		}
		return startOffset;
	}

	void ProgramBuilder::printClassdefTable(Logs::Report trace, const AtomStackFrame& frame) const
	{
		auto entry = trace.trace();

		entry.message.prefix << cdeftable.keyword(frame.atom) << ' ';
		frame.atom.appendCaption(entry.message.prefix, cdeftable);
		entry << " - type matrix, after instanciation - atom " << frame.atom.atomid;

		for (uint i = 0; i != frame.localVariablesCount(); ++i)
		{
			auto clid = CLID{frame.atomid, i};
			auto entry = trace.trace();

			if (cdeftable.hasClassdef(clid) or cdeftable.hasSubstitute(clid))
			{
				cdeftable.printClassdef(entry.message.message, clid, cdeftable.classdef(clid));
				entry.message.message.trimRight();

				if (cdeftable.hasSubstitute(clid))
					entry << " (local replacement)";

				if (frame.lvids[i].isConstexpr)
					entry << " (constexpr)";
			}
			else
			{
				entry << "    " << clid << ": !!INVALID CLID";
			}
		}
	}

	bool ProgramBuilder::readAndInstanciate(uint32_t offset)
	{
		currentProgram.each(*this, offset);
		return success;
	}

} // namespace Instanciate
} // namespace Pass
} // namespace Nany

namespace Nany
{

	bool Isolate::instanciate(Logs::Report report, const AnyString& entrypoint)
	{
		// lock the isolate
		MutexLocker locker{mutex};

		// try to find the entrypoint
		Atom* entrypointAtom = nullptr;
		{
			bool canContinue = true;
			classdefTable.atoms.root.eachChild(entrypoint, [&](Atom& child) -> bool
			{
				if (entrypointAtom != nullptr)
				{
					canContinue = false;
					report.error() << "failed to instanciate '" << entrypoint << "': multiple entry points found";
					return false;
				}
				entrypointAtom = &child;
				return true;
			});

			if (not canContinue)
				return false;
		}

		if (unlikely(nullptr == entrypointAtom))
		{
			report.ICE() << "failed to instanciate '" << entrypoint << "()': function not found";
			return false;
		}

		if (unlikely(entrypointAtom->type != Atom::Type::funcdef))
		{
			report.ICE() << "failed to instanciate '" << entrypoint << "': the atom is not a function";
			return false;
		}

		// parameters for the signature
		decltype(FuncOverloadMatch::result.params)  params;
		Logs::Message::Ptr newReport;

		ClassdefTableView cdeftblView{classdefTable};

		Pass::Instanciate::InstanciateData info{newReport, *entrypointAtom, cdeftblView, intrinsics, params};
		auto* program = Pass::Instanciate::InstanciateAtom(info);
		report.appendEntry(newReport);
		return (nullptr != program);
	}

} // namespace Nany
<|endoftext|>


<commit_before>#include "yebash.hpp"
#include "History.hpp"

#include "catch.hpp"
#include <initializer_list>
#include <iostream>
#include <algorithm>
#include <sstream>

using namespace yb;
using namespace std;

namespace {

History createHistory(initializer_list<string> const& commands) {
    stringstream ss;
    for (auto && command: commands) {
        ss << command << std::endl;
    }

    History history;
    history.read(ss);
    return history;
}

void tearDown() {
    std::stringstream output, ss;
    Printer printer(output);
    History history;
    history.read(ss);
    HistorySuggestion suggestion(history);
    yebash(suggestion, printer, '\n');
}
} // anon namespace

TEST_CASE( "No suggestions when history is empty", "[basic.empty_history]"  ) {

    auto testCharacter = [] (char const c) {
        History history = createHistory({});
        HistorySuggestion suggestion(history);

        std::stringstream output;
        Printer printer(output);

        auto result = yebash(suggestion, printer, c);

        REQUIRE(result == c);
        REQUIRE(output.str() == "");
    };

    string domain = "abcdefghijklmnopqrstuvwxyz01234567890-_";
    for_each(begin(domain), end(domain), testCharacter);

    tearDown();
}

TEST_CASE( "Order of commands from history is preserved", "[basic.history_order_preserved]"  ) {

    History history = createHistory({"abc1", "abc2"});
    HistorySuggestion suggestion(history);

    std::stringstream output;
    Printer printer(output);

    auto character = 'a';
    auto result = yebash(suggestion, printer, character);

    REQUIRE(result == character);
    REQUIRE(output.str() == "bc2");

    tearDown();
}

unsigned char rollSuggestions(HistorySuggestion &suggestion, Printer &printer, int n) {
    unsigned char result;
    for (int i = 0; i < n; i++) {
        result = yebash(suggestion, printer, 0x06);
    }
    return result;
}

TEST_CASE( "Suggestions can be switched", "[basic.browsing_suggestions]" ) {

    History history = createHistory({"a", "ab", "abc", "abcd", "bcd"});
    HistorySuggestion suggestion(history);

    std::stringstream output;
    Printer printer(output);

    yebash(suggestion, printer, 'a');

    SECTION( "one switch" ) {
        auto result = rollSuggestions(suggestion, printer, 1);
        REQUIRE(result == 0);
        REQUIRE(output.str() == "bcdbc");
    }

    SECTION( "two switches" ) {
        auto result = rollSuggestions(suggestion, printer, 2);
        REQUIRE(result == 0);
        REQUIRE(output.str() == "bcdbcb");
    }

    SECTION( "third switch to empty suggestion" ) {
        auto result = rollSuggestions(suggestion, printer, 3);
        REQUIRE(result == 0);
        REQUIRE(output.str() == "bcdbcb");
    }

    SECTION( "no more suggestions" ) {
        auto result = rollSuggestions(suggestion, printer, 4);
        REQUIRE(result == 0);
        REQUIRE(output.str() == "bcdbcb");
    }

    SECTION( "go back to the first suggestion" ) {
        auto result = rollSuggestions(suggestion, printer, 5);
        REQUIRE(result == 0);
        REQUIRE(output.str() == "bcdbcbbcd");
    }

    tearDown();
}
<commit_msg>added backspace test that fails<commit_after>#include "yebash.hpp"
#include "History.hpp"

#include "catch.hpp"
#include <initializer_list>
#include <iostream>
#include <algorithm>
#include <sstream>

using namespace yb;
using namespace std;

namespace {

History createHistory(initializer_list<string> const& commands) {
    stringstream ss;
    for (auto && command: commands) {
        ss << command << std::endl;
    }

    History history;
    history.read(ss);
    return history;
}

void tearDown() {
    std::stringstream output, ss;
    Printer printer(output);
    History history;
    history.read(ss);
    HistorySuggestion suggestion(history);
    yebash(suggestion, printer, '\n');
}
} // anon namespace

TEST_CASE( "No suggestions when history is empty", "[basic.empty_history]"  ) {

    auto testCharacter = [] (char const c) {
        History history = createHistory({});
        HistorySuggestion suggestion(history);

        std::stringstream output;
        Printer printer(output);

        auto result = yebash(suggestion, printer, c);

        REQUIRE(result == c);
        REQUIRE(output.str() == "");
    };

    string domain = "abcdefghijklmnopqrstuvwxyz01234567890-_";
    for_each(begin(domain), end(domain), testCharacter);

    tearDown();
}

TEST_CASE( "Order of commands from history is preserved", "[basic.history_order_preserved]"  ) {

    History history = createHistory({"abc1", "abc2"});
    HistorySuggestion suggestion(history);

    std::stringstream output;
    Printer printer(output);

    auto character = 'a';
    auto result = yebash(suggestion, printer, character);

    REQUIRE(result == character);
    REQUIRE(output.str() == "bc2");

    tearDown();
}

unsigned char rollSuggestions(HistorySuggestion &suggestion, Printer &printer, int n) {
    unsigned char result;
    for (int i = 0; i < n; i++) {
        result = yebash(suggestion, printer, 0x06);
    }
    return result;
}

TEST_CASE( "Suggestions can be switched", "[basic.browsing_suggestions]" ) {

    History history = createHistory({"a", "ab", "abc", "abcd", "bcd"});
    HistorySuggestion suggestion(history);

    std::stringstream output;
    Printer printer(output);

    yebash(suggestion, printer, 'a');

    SECTION( "one switch" ) {
        auto result = rollSuggestions(suggestion, printer, 1);
        REQUIRE(result == 0);
        REQUIRE(output.str() == "bcdbc");
    }

    SECTION( "two switches" ) {
        auto result = rollSuggestions(suggestion, printer, 2);
        REQUIRE(result == 0);
        REQUIRE(output.str() == "bcdbcb");
    }

    SECTION( "third switch to empty suggestion" ) {
        auto result = rollSuggestions(suggestion, printer, 3);
        REQUIRE(result == 0);
        REQUIRE(output.str() == "bcdbcb");
    }

    SECTION( "no more suggestions" ) {
        auto result = rollSuggestions(suggestion, printer, 4);
        REQUIRE(result == 0);
        REQUIRE(output.str() == "bcdbcb");
    }

    SECTION( "go back to the first suggestion" ) {
        auto result = rollSuggestions(suggestion, printer, 5);
        REQUIRE(result == 0);
        REQUIRE(output.str() == "bcdbcbbcd");
    }

    tearDown();
}

TEST_CASE( "Backspace invalidates suggestions", "[basic.backspace]" ) {

    History history = createHistory({"12345", "def", "trolo", "abc", "123"});
    HistorySuggestion suggestion(history);

    std::stringstream output;
    Printer printer(output);

    constexpr char backspace = 0x7f;

    SECTION( "go through history -> 1234" ) {
        yebash(suggestion, printer, '1');
        yebash(suggestion, printer, '2');
        yebash(suggestion, printer, '3');
        yebash(suggestion, printer, '4');
        REQUIRE(output.str() == "2335");
    }

    SECTION( "backspace -> 123" ) {
        yebash(suggestion, printer, backspace);
        REQUIRE(output.str() == "");
    }

    SECTION( "go forward again" ) {
        auto result = yebash(suggestion, printer, '4');
        REQUIRE(output.str() == "5");
    }

    tearDown();
}
<|endoftext|>


<commit_before>// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp

#include <Nazara/Core/Error.hpp>
#include <type_traits>

namespace Ndk
{
	inline World::World(bool addDefaultSystems)
	{
		if (addDefaultSystems)
			AddDefaultSystems();
	}

	inline World::World(World&& world) noexcept :
	HandledObject(std::move(world))
	{
		operator=(std::move(world));
	}

	inline BaseSystem& World::AddSystem(std::unique_ptr<BaseSystem>&& system)
	{
		NazaraAssert(system, "System must be valid");

		SystemIndex index = system->GetIndex();

		// Nous nous assurons que le vecteur de component est suffisamment grand pour contenir le nouveau component
		if (index >= m_systems.size())
			m_systems.resize(index + 1);

		// Affectation et retour du système
		m_systems[index] = std::move(system);
		m_systems[index]->SetWorld(this);

		Invalidate(); // On force une mise à jour de toutes les entités

		return *m_systems[index].get();
	}

	template<typename SystemType, typename... Args>
	SystemType& World::AddSystem(Args&&... args)
	{
		static_assert(std::is_base_of<BaseSystem, SystemType>::value, "SystemType is not a component");

		// Allocation et affectation du component
		std::unique_ptr<SystemType> ptr(new SystemType(std::forward(args)...));
		return static_cast<SystemType&>(AddSystem(std::move(ptr)));
	}

	inline World::EntityList World::CreateEntities(unsigned int count)
	{
		EntityList list;
		list.reserve(count);

		for (unsigned int i = 0; i < count; ++i)
			list.emplace_back(CreateEntity());

		return list;
	}

	inline const World::EntityList& World::GetEntities()
	{
		return m_aliveEntities;
	}

	inline BaseSystem& World::GetSystem(SystemIndex index)
	{
		///DOC: Le système doit être présent
		NazaraAssert(HasSystem(index), "This system is not part of the world");

		BaseSystem* system = m_systems[index].get();
		NazaraAssert(system, "Invalid system pointer");

		return *system;
	}

	template<typename SystemType>
	SystemType& World::GetSystem()
	{
		///DOC: Le système doit être présent
		static_assert(std::is_base_of<BaseSystem, SystemType>::value, "SystemType is not a system");

		SystemIndex index = GetSystemIndex<SystemType>();
		return static_cast<SystemType&>(GetSystem(index));
	}

	inline bool World::HasSystem(SystemIndex index) const
	{
		return index < m_systems.size() && m_systems[index];
	}

	template<typename SystemType>
	bool World::HasSystem() const
	{
		static_assert(std::is_base_of<BaseSystem, SystemType>::value, "SystemType is not a component");

		SystemIndex index = GetSystemIndex<SystemType>();
		return HasSystem(index);
	}

	inline void World::KillEntities(const EntityList& list)
	{
		for (const EntityHandle& entity : list)
			KillEntity(entity);
	}

	inline bool World::IsEntityValid(const Entity* entity) const
	{
		return entity && entity->GetWorld() == this && IsEntityIdValid(entity->GetId());
	}

	inline bool World::IsEntityIdValid(EntityId id) const
	{
		return id < m_entities.size() && m_entities[id].entity.IsValid();
	}

	inline void World::RemoveAllSystems()
	{
		m_systems.clear();
	}

	inline void World::RemoveSystem(SystemIndex index)
	{
		///DOC: N'a aucun effet si le système n'est pas présent
		if (HasSystem(index))
			m_systems[index].reset();
	}

	template<typename SystemType>
	void World::RemoveSystem()
	{
		static_assert(std::is_base_of<BaseSystem, SystemType>(), "SystemType is not a system");

		SystemIndex index = GetSystemIndex<SystemType>();
		RemoveSystem(index);
	}

	inline void World::Update(float elapsedTime)
	{
		Update(); //< Update entities

		// And then update systems
		for (auto& systemPtr : m_systems)
		{
			if (systemPtr)
				systemPtr->Update(elapsedTime);
		}
	}

	inline void World::Invalidate()
	{
		m_dirtyEntities.Resize(m_entities.size(), false);
		m_dirtyEntities.Set(true); // Activation de tous les bits
	}

	inline void World::Invalidate(EntityId id)
	{
		m_dirtyEntities.UnboundedSet(id, true);
	}

	inline World& World::operator=(World&& world) noexcept
	{
		m_aliveEntities  = std::move(world.m_aliveEntities);
		m_dirtyEntities  = std::move(world.m_dirtyEntities);
		m_freeIdList     = std::move(world.m_freeIdList);
		m_killedEntities = std::move(world.m_killedEntities);

		m_entities = std::move(world.m_entities);
		for (EntityBlock& block : m_entities)
			block.entity.SetWorld(this);

		m_systems = std::move(world.m_systems);
		for (const auto& systemPtr : m_systems)
			systemPtr->SetWorld(this);

		return *this;
	}
}
<commit_msg>Sdk/World: Fix compilation error when submitting arguments on system creation<commit_after>// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp

#include <Nazara/Core/Error.hpp>
#include <type_traits>

namespace Ndk
{
	inline World::World(bool addDefaultSystems)
	{
		if (addDefaultSystems)
			AddDefaultSystems();
	}

	inline World::World(World&& world) noexcept :
	HandledObject(std::move(world))
	{
		operator=(std::move(world));
	}

	inline BaseSystem& World::AddSystem(std::unique_ptr<BaseSystem>&& system)
	{
		NazaraAssert(system, "System must be valid");

		SystemIndex index = system->GetIndex();

		// Nous nous assurons que le vecteur de component est suffisamment grand pour contenir le nouveau component
		if (index >= m_systems.size())
			m_systems.resize(index + 1);

		// Affectation et retour du système
		m_systems[index] = std::move(system);
		m_systems[index]->SetWorld(this);

		Invalidate(); // On force une mise à jour de toutes les entités

		return *m_systems[index].get();
	}

	template<typename SystemType, typename... Args>
	SystemType& World::AddSystem(Args&&... args)
	{
		static_assert(std::is_base_of<BaseSystem, SystemType>::value, "SystemType is not a component");

		// Allocation et affectation du component
		std::unique_ptr<SystemType> ptr(new SystemType(std::forward<Args>(args)...));
		return static_cast<SystemType&>(AddSystem(std::move(ptr)));
	}

	inline World::EntityList World::CreateEntities(unsigned int count)
	{
		EntityList list;
		list.reserve(count);

		for (unsigned int i = 0; i < count; ++i)
			list.emplace_back(CreateEntity());

		return list;
	}

	inline const World::EntityList& World::GetEntities()
	{
		return m_aliveEntities;
	}

	inline BaseSystem& World::GetSystem(SystemIndex index)
	{
		///DOC: Le système doit être présent
		NazaraAssert(HasSystem(index), "This system is not part of the world");

		BaseSystem* system = m_systems[index].get();
		NazaraAssert(system, "Invalid system pointer");

		return *system;
	}

	template<typename SystemType>
	SystemType& World::GetSystem()
	{
		///DOC: Le système doit être présent
		static_assert(std::is_base_of<BaseSystem, SystemType>::value, "SystemType is not a system");

		SystemIndex index = GetSystemIndex<SystemType>();
		return static_cast<SystemType&>(GetSystem(index));
	}

	inline bool World::HasSystem(SystemIndex index) const
	{
		return index < m_systems.size() && m_systems[index];
	}

	template<typename SystemType>
	bool World::HasSystem() const
	{
		static_assert(std::is_base_of<BaseSystem, SystemType>::value, "SystemType is not a component");

		SystemIndex index = GetSystemIndex<SystemType>();
		return HasSystem(index);
	}

	inline void World::KillEntities(const EntityList& list)
	{
		for (const EntityHandle& entity : list)
			KillEntity(entity);
	}

	inline bool World::IsEntityValid(const Entity* entity) const
	{
		return entity && entity->GetWorld() == this && IsEntityIdValid(entity->GetId());
	}

	inline bool World::IsEntityIdValid(EntityId id) const
	{
		return id < m_entities.size() && m_entities[id].entity.IsValid();
	}

	inline void World::RemoveAllSystems()
	{
		m_systems.clear();
	}

	inline void World::RemoveSystem(SystemIndex index)
	{
		///DOC: N'a aucun effet si le système n'est pas présent
		if (HasSystem(index))
			m_systems[index].reset();
	}

	template<typename SystemType>
	void World::RemoveSystem()
	{
		static_assert(std::is_base_of<BaseSystem, SystemType>(), "SystemType is not a system");

		SystemIndex index = GetSystemIndex<SystemType>();
		RemoveSystem(index);
	}

	inline void World::Update(float elapsedTime)
	{
		Update(); //< Update entities

		// And then update systems
		for (auto& systemPtr : m_systems)
		{
			if (systemPtr)
				systemPtr->Update(elapsedTime);
		}
	}

	inline void World::Invalidate()
	{
		m_dirtyEntities.Resize(m_entities.size(), false);
		m_dirtyEntities.Set(true); // Activation de tous les bits
	}

	inline void World::Invalidate(EntityId id)
	{
		m_dirtyEntities.UnboundedSet(id, true);
	}

	inline World& World::operator=(World&& world) noexcept
	{
		m_aliveEntities  = std::move(world.m_aliveEntities);
		m_dirtyEntities  = std::move(world.m_dirtyEntities);
		m_freeIdList     = std::move(world.m_freeIdList);
		m_killedEntities = std::move(world.m_killedEntities);

		m_entities = std::move(world.m_entities);
		for (EntityBlock& block : m_entities)
			block.entity.SetWorld(this);

		m_systems = std::move(world.m_systems);
		for (const auto& systemPtr : m_systems)
			systemPtr->SetWorld(this);

		return *this;
	}
}
<|endoftext|>


<commit_before>AliAnalysisTaskSEDs *AddTaskDs()
{
  //
  // Test macro for the AliAnalysisTaskSE for Ds candidates

  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    ::Error("AddTaskDs", "No analysis manager to connect to.");
    return NULL;
  }

  // Aanalysis task
  AliAnalysisTaskSEDs *dsTask = new AliAnalysisTaskSEDs("DsAnalysis");
  dsTask->SetReadMC(kTRUE);
  dsTask->SetDebugLevel(0);
  mgr->AddTask(dsTask);

  //
  // Create containers for input/output
  AliAnalysisDataContainer *cinputDs = mgr->CreateContainer("cinputDs",TChain::Class(),
							    AliAnalysisManager::kInputContainer);

  TString outputfile = AliAnalysisManager::GetCommonFileName();
  outputfile += ":PWG3_D2H_InvMassDs";
  AliAnalysisDataContainer *coutputDs = mgr->CreateContainer("coutputDs",TList::Class(),
							     AliAnalysisManager::kOutputContainer,
							     outputfile.Data());

  mgr->ConnectInput(dsTask,0,mgr->GetCommonInputContainer());

  mgr->ConnectOutput(dsTask,1,coutputDs);

  return dsTask;
}
<commit_msg>Added flag readMC as an argument of AddTaskDs()<commit_after>AliAnalysisTaskSEDs *AddTaskDs(Bool_t readMC=kTRUE)
{
  //
  // Test macro for the AliAnalysisTaskSE for Ds candidates

  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    ::Error("AddTaskDs", "No analysis manager to connect to.");
    return NULL;
  }

  // Aanalysis task
  AliAnalysisTaskSEDs *dsTask = new AliAnalysisTaskSEDs("DsAnalysis");
  dsTask->SetReadMC(readMC);
  dsTask->SetDebugLevel(0);
  mgr->AddTask(dsTask);

  //
  // Create containers for input/output
  AliAnalysisDataContainer *cinputDs = mgr->CreateContainer("cinputDs",TChain::Class(),
							    AliAnalysisManager::kInputContainer);

  TString outputfile = AliAnalysisManager::GetCommonFileName();
  outputfile += ":PWG3_D2H_InvMassDs";
  AliAnalysisDataContainer *coutputDs = mgr->CreateContainer("coutputDs",TList::Class(),
							     AliAnalysisManager::kOutputContainer,
							     outputfile.Data());

  mgr->ConnectInput(dsTask,0,mgr->GetCommonInputContainer());

  mgr->ConnectOutput(dsTask,1,coutputDs);

  return dsTask;
}
<|endoftext|>


<commit_before>#include "schedulers/bulk_scheduler.h"
#include "schedulers/always_switch_scheduler.h"
#include "schedulers/never_switch_scheduler.h"
#include "schedulers/binary_throttle_scheduler.h"
#include "schedulers/wojtek_throttle_scheduler.h"
#include "schedulers/magic_throttle_scheduler.h"

#include "gflags/gflags.h"

DECLARE_bool(check_if_safe_ahead);
DEFINE_bool(always_switch, false, "");

DECLARE_string(throttle_scheduler);
DECLARE_string(switch_scheduler);

namespace schedulers {

BulkScheduler::BulkScheduler(const game::Race& race,
               game::RaceTracker& race_tracker,
               game::CarTracker& car_tracker,
               int time_limit)
    : race_(race), car_tracker_(car_tracker), race_tracker_(race_tracker), time_limit_(time_limit) {
  turbo_scheduler_.reset(new GreedyTurboScheduler(race_, car_tracker_));
  throttle_scheduler_.reset(CreateThrottleScheduler());
  switch_scheduler_.reset(CreateSwitchScheduler());

  bump_scheduler_.reset(
      new BumpScheduler(race_, race_tracker_, car_tracker_));
}

void BulkScheduler::Schedule(const game::CarState& state) {
  bump_scheduler_->Schedule(state);

  if (bump_scheduler_->HasTarget()) {
    command_ = bump_scheduler_->command();
    return;
  }
  // Bumper has priority over anything else.

  turbo_scheduler_->Schedule(state);
  switch_scheduler_->Schedule(state);

  // If we want to switch, schedule throttle for target lane bent
  auto state_with_switch = state;
  state_with_switch.set_switch_state(switch_scheduler_->ExpectedSwitch());
  throttle_scheduler_->Schedule(state_with_switch);

  if (car_tracker_.IsReady() && turbo_scheduler_->ShouldFireTurbo()) {
    command_ = game::Command(game::TurboToggle::kToggleOn);
  } else if (car_tracker_.IsReady() && switch_scheduler_->ShouldSwitch()) {
    command_ = game::Command(switch_scheduler_->SwitchDirection());
  } else {
    command_ = game::Command(throttle_scheduler_->throttle());
  }

  game::Command safe_command;
  if (FLAGS_check_if_safe_ahead &&
      !race_tracker_.IsSafeInFront(command_, &safe_command))
    command_ = safe_command;
}

void BulkScheduler::set_strategy(const Strategy& strategy) {
  strategy_ = strategy;
  throttle_scheduler_->set_strategy(strategy);
  switch_scheduler_->set_strategy(strategy);
  turbo_scheduler_->set_strategy(strategy);
}

void BulkScheduler::Overtake(const string& color) {
  printf("NOT IMPLEMENTED\n");
}

void BulkScheduler::IssuedCommand(const game::Command& command) {
  if (command.SwitchSet()) {
    printf("Switch\n");
    switch_scheduler_->Switched();
  } else if (command.TurboSet()) {
    printf("YABADABADUUUU\n");
    turbo_scheduler_->TurboUsed();
  }
}

ThrottleScheduler* BulkScheduler::CreateThrottleScheduler() {
  if (FLAGS_throttle_scheduler == "BinaryThrottleScheduler") {
    std::cout << "Using BinaryThrottleScheduler" << std::endl;
    return new BinaryThrottleScheduler(race_, car_tracker_, time_limit_);
  } else if (FLAGS_throttle_scheduler == "WojtekThrottleScheduler") {
    std::cout << "Using WojtekThrottleScheduler" << std::endl;
    return new WojtekThrottleScheduler(&race_, &car_tracker_);
  } else if (FLAGS_throttle_scheduler == "MagicThrottleScheduler") {
    std::cout << "Using " << FLAGS_throttle_scheduler << std::endl;
    return new MagicThrottleScheduler(race_, car_tracker_, time_limit_);
  }

  std::cerr << "UNKNOWN throttle scheduler: " << FLAGS_throttle_scheduler << std::endl;
  return new BinaryThrottleScheduler(race_, car_tracker_, time_limit_);
}

SwitchScheduler* BulkScheduler::CreateSwitchScheduler() {
  if (FLAGS_switch_scheduler == "ShortestPathSwitchScheduler") {
    std::cout << "Using ShortestPathSwitchScheduler" << std::endl;
    return new ShortestPathSwitchScheduler(race_, race_tracker_, car_tracker_);
  } else if (FLAGS_switch_scheduler == "AlwaysSwitchScheduler") {
    std::cout << "Using AlwaysSwitchScheduler" << std::endl;
    return new AlwaysSwitchScheduler(&race_.track());
  } else if (FLAGS_switch_scheduler == "NeverSwitchScheduler") {
    std::cout << "Using NeverSwitchScheduler" << std::endl;
    return new NeverSwitchScheduler();
  }

  std::cerr << "UNKNOWN switch scheduler: " << FLAGS_switch_scheduler << std::endl;
  return new ShortestPathSwitchScheduler(race_, race_tracker_, car_tracker_);
}

}  // namespace schedulers
<commit_msg>Allow to use switches and turbo even if model not learnt<commit_after>#include "schedulers/bulk_scheduler.h"
#include "schedulers/always_switch_scheduler.h"
#include "schedulers/never_switch_scheduler.h"
#include "schedulers/binary_throttle_scheduler.h"
#include "schedulers/wojtek_throttle_scheduler.h"
#include "schedulers/magic_throttle_scheduler.h"

#include "gflags/gflags.h"

DECLARE_bool(check_if_safe_ahead);
DEFINE_bool(always_switch, false, "");

DECLARE_string(throttle_scheduler);
DECLARE_string(switch_scheduler);

namespace schedulers {

BulkScheduler::BulkScheduler(const game::Race& race,
               game::RaceTracker& race_tracker,
               game::CarTracker& car_tracker,
               int time_limit)
    : race_(race), car_tracker_(car_tracker), race_tracker_(race_tracker), time_limit_(time_limit) {
  turbo_scheduler_.reset(new GreedyTurboScheduler(race_, car_tracker_));
  throttle_scheduler_.reset(CreateThrottleScheduler());
  switch_scheduler_.reset(CreateSwitchScheduler());

  bump_scheduler_.reset(
      new BumpScheduler(race_, race_tracker_, car_tracker_));
}

void BulkScheduler::Schedule(const game::CarState& state) {
  bump_scheduler_->Schedule(state);

  if (bump_scheduler_->HasTarget()) {
    command_ = bump_scheduler_->command();
    return;
  }
  // Bumper has priority over anything else.

  turbo_scheduler_->Schedule(state);
  switch_scheduler_->Schedule(state);

  // If we want to switch, schedule throttle for target lane bent
  auto state_with_switch = state;
  state_with_switch.set_switch_state(switch_scheduler_->ExpectedSwitch());
  throttle_scheduler_->Schedule(state_with_switch);

  if (turbo_scheduler_->ShouldFireTurbo()) {
    command_ = game::Command(game::TurboToggle::kToggleOn);
  } else if (switch_scheduler_->ShouldSwitch()) {
    command_ = game::Command(switch_scheduler_->SwitchDirection());
  } else {
    command_ = game::Command(throttle_scheduler_->throttle());
  }

  game::Command safe_command;
  if (FLAGS_check_if_safe_ahead &&
      !race_tracker_.IsSafeInFront(command_, &safe_command))
    command_ = safe_command;
}

void BulkScheduler::set_strategy(const Strategy& strategy) {
  strategy_ = strategy;
  throttle_scheduler_->set_strategy(strategy);
  switch_scheduler_->set_strategy(strategy);
  turbo_scheduler_->set_strategy(strategy);
}

void BulkScheduler::Overtake(const string& color) {
  printf("NOT IMPLEMENTED\n");
}

void BulkScheduler::IssuedCommand(const game::Command& command) {
  if (command.SwitchSet()) {
    printf("Switch\n");
    switch_scheduler_->Switched();
  } else if (command.TurboSet()) {
    printf("YABADABADUUUU\n");
    turbo_scheduler_->TurboUsed();
  }
}

ThrottleScheduler* BulkScheduler::CreateThrottleScheduler() {
  if (FLAGS_throttle_scheduler == "BinaryThrottleScheduler") {
    std::cout << "Using BinaryThrottleScheduler" << std::endl;
    return new BinaryThrottleScheduler(race_, car_tracker_, time_limit_);
  } else if (FLAGS_throttle_scheduler == "WojtekThrottleScheduler") {
    std::cout << "Using WojtekThrottleScheduler" << std::endl;
    return new WojtekThrottleScheduler(&race_, &car_tracker_);
  } else if (FLAGS_throttle_scheduler == "MagicThrottleScheduler") {
    std::cout << "Using " << FLAGS_throttle_scheduler << std::endl;
    return new MagicThrottleScheduler(race_, car_tracker_, time_limit_);
  }

  std::cerr << "UNKNOWN throttle scheduler: " << FLAGS_throttle_scheduler << std::endl;
  return new BinaryThrottleScheduler(race_, car_tracker_, time_limit_);
}

SwitchScheduler* BulkScheduler::CreateSwitchScheduler() {
  if (FLAGS_switch_scheduler == "ShortestPathSwitchScheduler") {
    std::cout << "Using ShortestPathSwitchScheduler" << std::endl;
    return new ShortestPathSwitchScheduler(race_, race_tracker_, car_tracker_);
  } else if (FLAGS_switch_scheduler == "AlwaysSwitchScheduler") {
    std::cout << "Using AlwaysSwitchScheduler" << std::endl;
    return new AlwaysSwitchScheduler(&race_.track());
  } else if (FLAGS_switch_scheduler == "NeverSwitchScheduler") {
    std::cout << "Using NeverSwitchScheduler" << std::endl;
    return new NeverSwitchScheduler();
  }

  std::cerr << "UNKNOWN switch scheduler: " << FLAGS_switch_scheduler << std::endl;
  return new ShortestPathSwitchScheduler(race_, race_tracker_, car_tracker_);
}

}  // namespace schedulers
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

#include <cstdint>
#include <limits>
#include <string>

#include "gtest/gtest.h"

#include "arrow/test-util.h"
#include "arrow/util/buffer.h"
#include "arrow/util/status.h"

using std::string;

namespace arrow {

class TestBuffer : public ::testing::Test {};

TEST_F(TestBuffer, Resize) {
  PoolBuffer buf;

  ASSERT_EQ(0, buf.size());
  ASSERT_OK(buf.Resize(100));
  ASSERT_EQ(100, buf.size());
  ASSERT_OK(buf.Resize(200));
  ASSERT_EQ(200, buf.size());

  // Make it smaller, too
  ASSERT_OK(buf.Resize(50));
  ASSERT_EQ(50, buf.size());
}

TEST_F(TestBuffer, ResizeOOM) {
  // realloc fails, even though there may be no explicit limit
  PoolBuffer buf;
  ASSERT_OK(buf.Resize(100));
  int64_t to_alloc = std::numeric_limits<int64_t>::max();
  ASSERT_RAISES(OutOfMemory, buf.Resize(to_alloc));
}

TEST_F(TestBuffer, EqualsWithSameContent) {
  MemoryPool* pool = default_memory_pool();
  int32_t bufferSize = 128 * 1024;
  uint8_t* rawBuffer1 = NULL;
  ASSERT_OK(pool->Allocate(bufferSize, &rawBuffer1));
  memset(rawBuffer1, 12, bufferSize);
  uint8_t* rawBuffer2 = NULL;
  ASSERT_OK(pool->Allocate(bufferSize, &rawBuffer2));
  memset(rawBuffer2, 12, bufferSize);
  uint8_t* rawBuffer3 = NULL;
  ASSERT_OK(pool->Allocate(bufferSize, &rawBuffer3));
  memset(rawBuffer3, 3, bufferSize);

  Buffer buffer1(rawBuffer1, bufferSize);
  Buffer buffer2(rawBuffer2, bufferSize);
  Buffer buffer3(rawBuffer3, bufferSize);
  ASSERT_TRUE(buffer1.Equals(buffer2));
  ASSERT_FALSE(buffer1.Equals(buffer3));
}

TEST_F(TestBuffer, EqualsWithSameBuffer) {
  MemoryPool* pool = default_memory_pool();
  int32_t bufferSize = 128 * 1024;
  uint8_t* rawBuffer = NULL;
  ASSERT_OK(pool->Allocate(bufferSize, &rawBuffer));

  Buffer buffer1(rawBuffer, bufferSize);
  Buffer buffer2(rawBuffer, bufferSize);
  ASSERT_TRUE(buffer1.Equals(buffer2));

  int64_t nbytes = bufferSize / 2;
  Buffer buffer3(rawBuffer, nbytes);
  ASSERT_TRUE(buffer1.Equals(buffer3, nbytes));
  ASSERT_FALSE(buffer1.Equals(buffer3, nbytes + 1));
}

}  // namespace arrow
<commit_msg>Fixed some comments<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

#include <cstdint>
#include <limits>
#include <string>

#include "gtest/gtest.h"

#include "arrow/test-util.h"
#include "arrow/util/buffer.h"
#include "arrow/util/status.h"

using std::string;

namespace arrow {

class TestBuffer : public ::testing::Test {};

TEST_F(TestBuffer, Resize) {
  PoolBuffer buf;

  ASSERT_EQ(0, buf.size());
  ASSERT_OK(buf.Resize(100));
  ASSERT_EQ(100, buf.size());
  ASSERT_OK(buf.Resize(200));
  ASSERT_EQ(200, buf.size());

  // Make it smaller, too
  ASSERT_OK(buf.Resize(50));
  ASSERT_EQ(50, buf.size());
}

TEST_F(TestBuffer, ResizeOOM) {
  // realloc fails, even though there may be no explicit limit
  PoolBuffer buf;
  ASSERT_OK(buf.Resize(100));
  int64_t to_alloc = std::numeric_limits<int64_t>::max();
  ASSERT_RAISES(OutOfMemory, buf.Resize(to_alloc));
}

TEST_F(TestBuffer, EqualsWithSameContent) {
  MemoryPool* pool = default_memory_pool();
  const int32_t bufferSize = 128 * 1024;
  uint8_t* rawBuffer1;
  ASSERT_OK(pool->Allocate(bufferSize, &rawBuffer1));
  memset(rawBuffer1, 12, bufferSize);
  uint8_t* rawBuffer2;
  ASSERT_OK(pool->Allocate(bufferSize, &rawBuffer2));
  memset(rawBuffer2, 12, bufferSize);
  uint8_t* rawBuffer3;
  ASSERT_OK(pool->Allocate(bufferSize, &rawBuffer3));
  memset(rawBuffer3, 3, bufferSize);

  Buffer buffer1(rawBuffer1, bufferSize);
  Buffer buffer2(rawBuffer2, bufferSize);
  Buffer buffer3(rawBuffer3, bufferSize);
  ASSERT_TRUE(buffer1.Equals(buffer2));
  ASSERT_FALSE(buffer1.Equals(buffer3));
}

TEST_F(TestBuffer, EqualsWithSameBuffer) {
  MemoryPool* pool = default_memory_pool();
  const int32_t bufferSize = 128 * 1024;
  uint8_t* rawBuffer;
  ASSERT_OK(pool->Allocate(bufferSize, &rawBuffer));
  memset(rawBuffer, 111, bufferSize);

  Buffer buffer1(rawBuffer, bufferSize);
  Buffer buffer2(rawBuffer, bufferSize);
  ASSERT_TRUE(buffer1.Equals(buffer2));

  const int64_t nbytes = bufferSize / 2;
  Buffer buffer3(rawBuffer, nbytes);
  ASSERT_TRUE(buffer1.Equals(buffer3, nbytes));
  ASSERT_FALSE(buffer1.Equals(buffer3, nbytes + 1));
}

}  // namespace arrow
<|endoftext|>


<commit_before>#include "Particles/ParticleSystem.h"

#include "Particles/ParticleData.h"

#include <iostream>

namespace particles {

/* ParticleSystem */

ParticleSystem::ParticleSystem(int maxCount) : emitRate(0.f), m_dt(0.f) {
	m_particles = new ParticleData(maxCount);
}

ParticleSystem::~ParticleSystem() {
	delete m_particles;

	for (auto s : m_spawners) {
		delete s;
	}

	for (auto g : m_generators) {
		delete g;
	}

	for (auto u : m_updaters) {
		delete u;
	}
}

void ParticleSystem::emitWithRate(float dt) {
	m_dt += dt;

	int maxNewParticles = 0;

	if (m_dt * emitRate > 1.0f) {
		maxNewParticles = static_cast<int>(m_dt * emitRate);
		m_dt -= maxNewParticles / emitRate;
	}

	if (maxNewParticles == 0) return;

	emitParticles(maxNewParticles);
}

void ParticleSystem::emitParticles(int count) {
	if (m_spawners.size() == 0) return;

	const int startId = m_particles->countAlive;
	const int endId = std::min(startId + count, m_particles->count - 1);
	const int newParticles = endId - startId;

	const int nSpawners = static_cast<int>(m_spawners.size());
	const int spawnerCount = newParticles / nSpawners;
	const int remainder = newParticles - spawnerCount * nSpawners;
	int spawnerStartId = startId;
	for (int i = 0; i < nSpawners; ++i) {
		int numberToSpawn = (i < remainder) ? spawnerCount + 1 : spawnerCount;
		m_spawners[i]->spawn(m_particles, spawnerStartId, spawnerStartId + numberToSpawn);
		spawnerStartId += numberToSpawn;
	}

	m_spawners[0]->spawn(m_particles, startId, endId);

	for (auto &generator : m_generators) {
		generator->generate(m_particles, startId, endId);
	}

	m_particles->countAlive += newParticles;
}

void ParticleSystem::update(const sf::Time &dt) {
	if (emitRate > 0.0f) {
		emitWithRate(dt.asSeconds());
	}

	for (int i = 0; i < m_particles->countAlive; ++i) {
		m_particles->acc[i] = { 0.0f, 0.0f };
	}

	for (auto & updater : m_updaters) {
		updater->update(m_particles, dt.asSeconds());
	}
}

void ParticleSystem::reset() {
	m_particles->countAlive = 0;
}

/* PointParticleSystem */

PointParticleSystem::PointParticleSystem(int maxCount) : ParticleSystem(maxCount) {
	m_vertices = sf::VertexArray(sf::Points, maxCount);
}

void PointParticleSystem::render(sf::RenderTarget &renderTarget) {
	updateVertices();

	sf::RenderStates states = sf::RenderStates::Default;

	const sf::Vertex *ver = &m_vertices[0];
	renderTarget.draw(ver, m_particles->countAlive, sf::Points, states);
}

void PointParticleSystem::updateVertices() {
	for (int i = 0; i < m_particles->countAlive; ++i) {
		m_vertices[i].position = m_particles->pos[i];
		m_vertices[i].color = m_particles->col[i];
	}
}

/* TextureParticleSystem */

TextureParticleSystem::TextureParticleSystem(int maxCount, sf::Texture *texture) : ParticleSystem(maxCount), m_texture(texture) {
	m_vertices = sf::VertexArray(sf::Quads, maxCount * 4);

	float x = static_cast<float>(m_texture->getSize().x);
	float y = static_cast<float>(m_texture->getSize().y);

	for (int i = 0; i < m_particles->count; ++i) {
		m_vertices[4 * i + 0].texCoords = sf::Vector2f(0.f, 0.f);
		m_vertices[4 * i + 1].texCoords = sf::Vector2f(x, 0.f);
		m_vertices[4 * i + 2].texCoords = sf::Vector2f(x, y);
		m_vertices[4 * i + 3].texCoords = sf::Vector2f(0.f, y);

		m_vertices[4 * i + 0].color = sf::Color::White;
		m_vertices[4 * i + 1].color = sf::Color::White;
		m_vertices[4 * i + 2].color = sf::Color::White;
		m_vertices[4 * i + 3].color = sf::Color::White;
	}

	additiveBlendMode = false;
}

void TextureParticleSystem::setTexture(sf::Texture *texture) {
	m_texture = texture;

	float x = static_cast<float>(m_texture->getSize().x);
	float y = static_cast<float>(m_texture->getSize().y);

	for (int i = 0; i < m_particles->count; ++i) {
		m_vertices[4 * i + 0].texCoords = sf::Vector2f(0.f, 0.f);
		m_vertices[4 * i + 1].texCoords = sf::Vector2f(x, 0.f);
		m_vertices[4 * i + 2].texCoords = sf::Vector2f(x, y);
		m_vertices[4 * i + 3].texCoords = sf::Vector2f(0.f, y);
	}
}

void TextureParticleSystem::updateVertices() {
	for (int i = 0; i < m_particles->countAlive; ++i) {
		float size = 0.5f * m_particles->size[i].x;
		float angle = m_particles->angle[i].x;

		m_vertices[4 * i + 0].position.x = -size;	m_vertices[4 * i + 0].position.y = -size;
		m_vertices[4 * i + 1].position.x = +size;	m_vertices[4 * i + 1].position.y = -size;
		m_vertices[4 * i + 2].position.x = +size;	m_vertices[4 * i + 2].position.y = +size;
		m_vertices[4 * i + 3].position.x = -size;	m_vertices[4 * i + 3].position.y = +size;

		if (angle != 0.f) {
			float sin = std::sin(angle); float cos = std::cos(angle);

			for (int j = 0; j < 4; ++j) {
				float x = m_vertices[4 * i + j].position.x;
				float y = m_vertices[4 * i + j].position.y;

				m_vertices[4 * i + j].position.x = cos * x - sin * y;
				m_vertices[4 * i + j].position.y = sin * x + cos * y;
			}
		}

		m_vertices[4 * i + 0].position.x += m_particles->pos[i].x;	m_vertices[4 * i + 0].position.y += m_particles->pos[i].y;
		m_vertices[4 * i + 1].position.x += m_particles->pos[i].x;	m_vertices[4 * i + 1].position.y += m_particles->pos[i].y;
		m_vertices[4 * i + 2].position.x += m_particles->pos[i].x;	m_vertices[4 * i + 2].position.y += m_particles->pos[i].y;
		m_vertices[4 * i + 3].position.x += m_particles->pos[i].x;	m_vertices[4 * i + 3].position.y += m_particles->pos[i].y;

		m_vertices[4 * i + 0].color = m_particles->col[i];
		m_vertices[4 * i + 1].color = m_particles->col[i];
		m_vertices[4 * i + 2].color = m_particles->col[i];
		m_vertices[4 * i + 3].color = m_particles->col[i];
	}
}

void TextureParticleSystem::render(sf::RenderTarget &renderTarget) {
	updateVertices();

	sf::RenderStates states = sf::RenderStates::Default;

	if (additiveBlendMode) {
		states.blendMode = sf::BlendAdd;
	}

	states.texture = m_texture;

	const sf::Vertex *ver = &m_vertices[0];
	renderTarget.draw(ver, m_particles->countAlive * 4, sf::Quads, states);
}

/* SpriteSheetParticleSystem */

void SpriteSheetParticleSystem::render(sf::RenderTarget &renderTarget) {
	updateVertices();

	sf::RenderStates states = sf::RenderStates::Default;

	if (additiveBlendMode) {
		states.blendMode = sf::BlendAdd;
	}

	states.texture = m_texture;

	const sf::Vertex *ver = &m_vertices[0];
	renderTarget.draw(ver, m_particles->countAlive * 4, sf::Quads, states);
}

void SpriteSheetParticleSystem::updateVertices() {
	TextureParticleSystem::updateVertices();

	for (int i = 0; i < m_particles->countAlive; ++i) {
		float left = static_cast<float>(m_particles->texCoords[i].left);
		float top = static_cast<float>(m_particles->texCoords[i].top);
		float width = static_cast<float>(m_particles->texCoords[i].width);
		float height = static_cast<float>(m_particles->texCoords[i].height);

		m_vertices[4 * i + 0].texCoords = sf::Vector2f(left, top);
		m_vertices[4 * i + 1].texCoords = sf::Vector2f(left + width, top);
		m_vertices[4 * i + 2].texCoords = sf::Vector2f(left + width, top + height);
		m_vertices[4 * i + 3].texCoords = sf::Vector2f(left, top + height);
	}
}

/* MetaballParticleSystem */

const std::string vertexShader = \
	"void main()" \
	"{" \
	"    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;" \
	"    gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;" \
	"    gl_FrontColor = gl_Color;" \
	"}";

const std::string fragmentShader = \
	"uniform sampler2D texture;" \
	"uniform vec4 customColor;" \
	"uniform float threshold;" \
	"" \
	"void main()" \
	"{" \
	"    vec4 pixel = texture2D(texture, gl_TexCoord[0].xy);" \
	"    if (pixel.a > threshold) {" \
	"        gl_FragColor = customColor;" \
	"    }" \
	"    else {" \
	"        gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);" \
	"    }" \
	"}";

MetaballParticleSystem::MetaballParticleSystem(int maxCount, sf::Texture *texture, int windowWidth, int windowHeight) : TextureParticleSystem(maxCount, texture) {
	additiveBlendMode = true;
	m_shader.setUniform("texture", sf::Shader::CurrentTexture);
	m_shader.loadFromMemory(vertexShader, fragmentShader);
	m_renderTexture.create(windowWidth, windowHeight);
}

void MetaballParticleSystem::render(sf::RenderTarget &renderTarget) {
	updateVertices();

	sf::RenderStates states = sf::RenderStates::Default;
	states.blendMode = sf::BlendAdd;

	states.texture = m_texture;

	const sf::Vertex *ver = &m_vertices[0];

	sf::View oldView = renderTarget.getView();
	sf::View defaultView = renderTarget.getDefaultView();

	m_renderTexture.setView(oldView);
	m_renderTexture.clear(sf::Color(0, 0, 0, 0));
	m_renderTexture.draw(ver, m_particles->countAlive * 4, sf::Quads, states);
	m_renderTexture.display();
	m_sprite.setTexture(m_renderTexture.getTexture());
	sf::Glsl::Vec4 colorVec = sf::Glsl::Vec4(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f);
	m_shader.setUniform("customColor", colorVec);
	m_shader.setUniform("threshold", threshold);

	renderTarget.setView(defaultView);
	renderTarget.draw(m_sprite, &m_shader);
	renderTarget.setView(oldView);
}

}<commit_msg>Fix include<commit_after>#include "Particles/ParticleSystem.h"

#include "Particles/ParticleData.h"
#include "Particles/ParticleHelpers.h"

namespace particles {

/* ParticleSystem */

ParticleSystem::ParticleSystem(int maxCount) : emitRate(0.f), m_dt(0.f) {
	m_particles = new ParticleData(maxCount);
}

ParticleSystem::~ParticleSystem() {
	delete m_particles;

	for (auto s : m_spawners) {
		delete s;
	}

	for (auto g : m_generators) {
		delete g;
	}

	for (auto u : m_updaters) {
		delete u;
	}
}

void ParticleSystem::emitWithRate(float dt) {
	m_dt += dt;

	int maxNewParticles = 0;

	if (m_dt * emitRate > 1.0f) {
		maxNewParticles = static_cast<int>(m_dt * emitRate);
		m_dt -= maxNewParticles / emitRate;
	}

	if (maxNewParticles == 0) return;

	emitParticles(maxNewParticles);
}

void ParticleSystem::emitParticles(int count) {
	if (m_spawners.size() == 0) return;

	const int startId = m_particles->countAlive;
	const int endId = std::min(startId + count, m_particles->count - 1);
	const int newParticles = endId - startId;

	const int nSpawners = static_cast<int>(m_spawners.size());
	const int spawnerCount = newParticles / nSpawners;
	const int remainder = newParticles - spawnerCount * nSpawners;
	int spawnerStartId = startId;
	for (int i = 0; i < nSpawners; ++i) {
		int numberToSpawn = (i < remainder) ? spawnerCount + 1 : spawnerCount;
		m_spawners[i]->spawn(m_particles, spawnerStartId, spawnerStartId + numberToSpawn);
		spawnerStartId += numberToSpawn;
	}

	m_spawners[0]->spawn(m_particles, startId, endId);

	for (auto &generator : m_generators) {
		generator->generate(m_particles, startId, endId);
	}

	m_particles->countAlive += newParticles;
}

void ParticleSystem::update(const sf::Time &dt) {
	if (emitRate > 0.0f) {
		emitWithRate(dt.asSeconds());
	}

	for (int i = 0; i < m_particles->countAlive; ++i) {
		m_particles->acc[i] = { 0.0f, 0.0f };
	}

	for (auto & updater : m_updaters) {
		updater->update(m_particles, dt.asSeconds());
	}
}

void ParticleSystem::reset() {
	m_particles->countAlive = 0;
}

/* PointParticleSystem */

PointParticleSystem::PointParticleSystem(int maxCount) : ParticleSystem(maxCount) {
	m_vertices = sf::VertexArray(sf::Points, maxCount);
}

void PointParticleSystem::render(sf::RenderTarget &renderTarget) {
	updateVertices();

	sf::RenderStates states = sf::RenderStates::Default;

	const sf::Vertex *ver = &m_vertices[0];
	renderTarget.draw(ver, m_particles->countAlive, sf::Points, states);
}

void PointParticleSystem::updateVertices() {
	for (int i = 0; i < m_particles->countAlive; ++i) {
		m_vertices[i].position = m_particles->pos[i];
		m_vertices[i].color = m_particles->col[i];
	}
}

/* TextureParticleSystem */

TextureParticleSystem::TextureParticleSystem(int maxCount, sf::Texture *texture) : ParticleSystem(maxCount), m_texture(texture) {
	m_vertices = sf::VertexArray(sf::Quads, maxCount * 4);

	float x = static_cast<float>(m_texture->getSize().x);
	float y = static_cast<float>(m_texture->getSize().y);

	for (int i = 0; i < m_particles->count; ++i) {
		m_vertices[4 * i + 0].texCoords = sf::Vector2f(0.f, 0.f);
		m_vertices[4 * i + 1].texCoords = sf::Vector2f(x, 0.f);
		m_vertices[4 * i + 2].texCoords = sf::Vector2f(x, y);
		m_vertices[4 * i + 3].texCoords = sf::Vector2f(0.f, y);

		m_vertices[4 * i + 0].color = sf::Color::White;
		m_vertices[4 * i + 1].color = sf::Color::White;
		m_vertices[4 * i + 2].color = sf::Color::White;
		m_vertices[4 * i + 3].color = sf::Color::White;
	}

	additiveBlendMode = false;
}

void TextureParticleSystem::setTexture(sf::Texture *texture) {
	m_texture = texture;

	float x = static_cast<float>(m_texture->getSize().x);
	float y = static_cast<float>(m_texture->getSize().y);

	for (int i = 0; i < m_particles->count; ++i) {
		m_vertices[4 * i + 0].texCoords = sf::Vector2f(0.f, 0.f);
		m_vertices[4 * i + 1].texCoords = sf::Vector2f(x, 0.f);
		m_vertices[4 * i + 2].texCoords = sf::Vector2f(x, y);
		m_vertices[4 * i + 3].texCoords = sf::Vector2f(0.f, y);
	}
}

void TextureParticleSystem::updateVertices() {
	for (int i = 0; i < m_particles->countAlive; ++i) {
		float size = 0.5f * m_particles->size[i].x;
		float angle = m_particles->angle[i].x;

		m_vertices[4 * i + 0].position.x = -size;	m_vertices[4 * i + 0].position.y = -size;
		m_vertices[4 * i + 1].position.x = +size;	m_vertices[4 * i + 1].position.y = -size;
		m_vertices[4 * i + 2].position.x = +size;	m_vertices[4 * i + 2].position.y = +size;
		m_vertices[4 * i + 3].position.x = -size;	m_vertices[4 * i + 3].position.y = +size;

		if (angle != 0.f) {
			float sin = std::sin(angle); float cos = std::cos(angle);

			for (int j = 0; j < 4; ++j) {
				float x = m_vertices[4 * i + j].position.x;
				float y = m_vertices[4 * i + j].position.y;

				m_vertices[4 * i + j].position.x = cos * x - sin * y;
				m_vertices[4 * i + j].position.y = sin * x + cos * y;
			}
		}

		m_vertices[4 * i + 0].position.x += m_particles->pos[i].x;	m_vertices[4 * i + 0].position.y += m_particles->pos[i].y;
		m_vertices[4 * i + 1].position.x += m_particles->pos[i].x;	m_vertices[4 * i + 1].position.y += m_particles->pos[i].y;
		m_vertices[4 * i + 2].position.x += m_particles->pos[i].x;	m_vertices[4 * i + 2].position.y += m_particles->pos[i].y;
		m_vertices[4 * i + 3].position.x += m_particles->pos[i].x;	m_vertices[4 * i + 3].position.y += m_particles->pos[i].y;

		m_vertices[4 * i + 0].color = m_particles->col[i];
		m_vertices[4 * i + 1].color = m_particles->col[i];
		m_vertices[4 * i + 2].color = m_particles->col[i];
		m_vertices[4 * i + 3].color = m_particles->col[i];
	}
}

void TextureParticleSystem::render(sf::RenderTarget &renderTarget) {
	updateVertices();

	sf::RenderStates states = sf::RenderStates::Default;

	if (additiveBlendMode) {
		states.blendMode = sf::BlendAdd;
	}

	states.texture = m_texture;

	const sf::Vertex *ver = &m_vertices[0];
	renderTarget.draw(ver, m_particles->countAlive * 4, sf::Quads, states);
}

/* SpriteSheetParticleSystem */

void SpriteSheetParticleSystem::render(sf::RenderTarget &renderTarget) {
	updateVertices();

	sf::RenderStates states = sf::RenderStates::Default;

	if (additiveBlendMode) {
		states.blendMode = sf::BlendAdd;
	}

	states.texture = m_texture;

	const sf::Vertex *ver = &m_vertices[0];
	renderTarget.draw(ver, m_particles->countAlive * 4, sf::Quads, states);
}

void SpriteSheetParticleSystem::updateVertices() {
	TextureParticleSystem::updateVertices();

	for (int i = 0; i < m_particles->countAlive; ++i) {
		float left = static_cast<float>(m_particles->texCoords[i].left);
		float top = static_cast<float>(m_particles->texCoords[i].top);
		float width = static_cast<float>(m_particles->texCoords[i].width);
		float height = static_cast<float>(m_particles->texCoords[i].height);

		m_vertices[4 * i + 0].texCoords = sf::Vector2f(left, top);
		m_vertices[4 * i + 1].texCoords = sf::Vector2f(left + width, top);
		m_vertices[4 * i + 2].texCoords = sf::Vector2f(left + width, top + height);
		m_vertices[4 * i + 3].texCoords = sf::Vector2f(left, top + height);
	}
}

/* MetaballParticleSystem */

const std::string vertexShader = \
	"void main()" \
	"{" \
	"    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;" \
	"    gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;" \
	"    gl_FrontColor = gl_Color;" \
	"}";

const std::string fragmentShader = \
	"uniform sampler2D texture;" \
	"uniform vec4 customColor;" \
	"uniform float threshold;" \
	"" \
	"void main()" \
	"{" \
	"    vec4 pixel = texture2D(texture, gl_TexCoord[0].xy);" \
	"    if (pixel.a > threshold) {" \
	"        gl_FragColor = customColor;" \
	"    }" \
	"    else {" \
	"        gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);" \
	"    }" \
	"}";

MetaballParticleSystem::MetaballParticleSystem(int maxCount, sf::Texture *texture, int windowWidth, int windowHeight) : TextureParticleSystem(maxCount, texture) {
	additiveBlendMode = true;
	m_shader.setUniform("texture", sf::Shader::CurrentTexture);
	m_shader.loadFromMemory(vertexShader, fragmentShader);
	m_renderTexture.create(windowWidth, windowHeight);
}

void MetaballParticleSystem::render(sf::RenderTarget &renderTarget) {
	updateVertices();

	sf::RenderStates states = sf::RenderStates::Default;
	states.blendMode = sf::BlendAdd;

	states.texture = m_texture;

	const sf::Vertex *ver = &m_vertices[0];

	sf::View oldView = renderTarget.getView();
	sf::View defaultView = renderTarget.getDefaultView();

	m_renderTexture.setView(oldView);
	m_renderTexture.clear(sf::Color(0, 0, 0, 0));
	m_renderTexture.draw(ver, m_particles->countAlive * 4, sf::Quads, states);
	m_renderTexture.display();
	m_sprite.setTexture(m_renderTexture.getTexture());
	sf::Glsl::Vec4 colorVec = sf::Glsl::Vec4(color.r / 255.f, color.g / 255.f, color.b / 255.f, color.a / 255.f);
	m_shader.setUniform("customColor", colorVec);
	m_shader.setUniform("threshold", threshold);

	renderTarget.setView(defaultView);
	renderTarget.draw(m_sprite, &m_shader);
	renderTarget.setView(oldView);
}

}<|endoftext|>


<commit_before><commit_msg>cid#1254675 Uncaught exception<commit_after><|endoftext|>