<commit_before>#include "ffmpeg_video_source.h"
extern "C" {
#include <libavutil/imgutils.h>
}

namespace gg
{

VideoSourceFFmpeg::VideoSourceFFmpeg()
{
    // nop
}

VideoSourceFFmpeg::VideoSourceFFmpeg(std::string source_path,
                                     enum ColourSpace colour_space,
                                     bool use_refcount)
    : IVideoSource(colour_space)
    , _source_path(source_path)
    , _avformat_context(nullptr)
    , _avstream_idx(-1)
    , _use_refcount(use_refcount)
    , _avstream(nullptr)
    , _avcodec_context(nullptr)
    , _avframe(nullptr)
    , _avframe_converted(nullptr)
    , _sws_context(nullptr)
    , _daemon(nullptr)
{
    int ret = 0;
    std::string error_msg = "";

    av_register_all();

    if (avformat_open_input(&_avformat_context, _source_path.c_str(),
                            nullptr, nullptr) < 0)
    {
        error_msg.append("Could not open video source ")
                 .append(_source_path);
        throw VideoSourceError(error_msg);
    }

    if (avformat_find_stream_info(_avformat_context, nullptr) < 0)
        throw VideoSourceError("Could not find stream information");

    if (open_codec_context(&_avstream_idx, _avformat_context,
                           AVMEDIA_TYPE_VIDEO, error_msg) >= 0)
    {
        _avstream = _avformat_context->streams[_avstream_idx];
        _avcodec_context = _avstream->codec;

        /* allocate image where the decoded image will be put */
        _width = _avcodec_context->width;
        _height = _avcodec_context->height;
        _avpixel_format = _avcodec_context->pix_fmt;
        ret = av_image_alloc(_data_buffer, _data_buffer_linesizes,
                             _width, _height, _avpixel_format, 1);
        if (ret < 0)
            throw VideoSourceError("Could not allocate"
                                   " raw video buffer");
        _data_buffer_length = ret;
    }
    else
        throw VideoSourceError(error_msg);

    if (_avstream == nullptr)
        throw VideoSourceError("Could not find video stream in source");

    _avframe = av_frame_alloc();
    if (_avframe == nullptr)
        throw VideoSourceError("Could not allocate frame");

    /* initialize packet, set data to NULL, let the demuxer fill it */
    av_init_packet(&_avpacket);
    _avpacket.data = nullptr;
    _avpacket.size = 0;

    AVPixelFormat target_avpixel_format;
    switch(_colour)
    {
    case BGRA:
        target_avpixel_format = AV_PIX_FMT_BGRA;
        break;
    case I420:
        target_avpixel_format = AV_PIX_FMT_YUV420P;
        break;
    case UYVY:
        target_avpixel_format = AV_PIX_FMT_UYVY422;
        break;
    default:
        throw VideoSourceError("Target colour space not supported");
    }
    if (_avpixel_format != target_avpixel_format)
    {
        switch(_avpixel_format)
        {
        case AV_PIX_FMT_BGRA:
            _stride[0] = 4 * _width;
            break;
        case AV_PIX_FMT_UYVY422:
            _stride[0] = 2 * _width;
            break;
        case AV_PIX_FMT_YUV420P:
            // TODO: 1) is this correct? 2) odd width?
            _stride[0] = 1.5 * _width;
            break;
        default:
            throw VideoSourceError("Source colour space not supported");
        }
        _avframe_converted = av_frame_alloc();
        if (_avframe_converted == nullptr)
            throw VideoSourceError("Could not allocate conversion frame");
        _avframe_converted->format = target_avpixel_format;
        _avframe_converted->width  = _width;
        _avframe_converted->height = _height;
        int pixel_depth;
        switch(target_avpixel_format)
        {
        case AV_PIX_FMT_BGRA:
            pixel_depth = 32; // bits-per-pixel
            break;
        case AV_PIX_FMT_YUV420P:
            pixel_depth = 12; // bits-per-pixel
            /* TODO #54 - alignment by _pixel_depth causes problems
             * due to buffer size mismatches between EpiphanSDK and
             * FFmpeg, hence manually filling in linesizes (based on
             * debugging measurements), in conj. with
             * av_image_fill_pointers below
             */
            _avframe_converted->linesize[0] = _avframe_converted->width;
            _avframe_converted->linesize[1] = _avframe_converted->width / 2;
            _avframe_converted->linesize[2] = _avframe_converted->width / 2;
            break;
        case AV_PIX_FMT_UYVY422:
            pixel_depth = 16; // bits-per-pixel
            break;
        default:
            throw VideoSourceError("Colour space not supported");
        }
        ret = av_frame_get_buffer(_avframe_converted, pixel_depth);
        if (ret < 0)
            throw VideoSourceError("Could not allocate conversion buffer");

        _sws_context = sws_getContext(
                    _width, _height, _avpixel_format,
                    _width, _height, target_avpixel_format,
                    0, nullptr, nullptr, nullptr);
        if (_sws_context == nullptr)
            throw VideoSourceError("Could not allocate Sws context");
    }

    _daemon = new gg::BroadcastDaemon(this);
    _daemon->start(get_frame_rate());
}

VideoSourceFFmpeg::~VideoSourceFFmpeg()
{
    delete _daemon;

    if (_sws_context != nullptr)
        sws_freeContext(_sws_context);
    avcodec_close(_avcodec_context);
    avformat_close_input(&_avformat_context);
    av_frame_free(&_avframe);
    if (_avframe_converted != nullptr)
        av_frame_free(&_avframe_converted);
    av_free(_data_buffer[0]);
    _data_buffer_length = 0;
}

bool VideoSourceFFmpeg::get_frame_dimensions(int & width, int & height)
{
    if (this->_width > 0 and this->_height > 0)
    {
        width = this->_width;
        height = this->_height;
        return true;
    }
    else
        return false;
}

bool VideoSourceFFmpeg::get_frame(VideoFrame & frame)
{
    if (av_read_frame(_avformat_context, &_avpacket) < 0)
        return false;

    int ret = 0, got_frame;
    bool success = true;
    AVPacket orig_pkt = _avpacket;
    size_t passes = 0;
    do
    {
        ret = decode_packet(&got_frame, 0);
        if (ret < 0)
        {
            success = false;
            break;
        }
        _avpacket.data += ret;
        _avpacket.size -= ret;

        // need to convert pixel format?
        uint8_t ** data_ptr = nullptr;
        int * data_linesize = nullptr;
        if (_sws_context != nullptr)
        {
            sws_scale(_sws_context,
                      _avframe->data, _stride,
                      0, _height,
                      _avframe_converted->data, _avframe_converted->linesize
                      );
            data_ptr = _avframe_converted->data;
            data_linesize = _avframe_converted->linesize;
        }
        else
        {
            data_ptr = _avframe->data;
            data_linesize = _avframe->linesize;
        }

        /* copy decoded frame to destination buffer:
         * this is required since rawvideo expects non aligned data */
        av_image_copy(_data_buffer, _data_buffer_linesizes,
                      const_cast<const uint8_t **>(data_ptr), data_linesize,
                      _avpixel_format, _width, _height);

        passes++;
    }
    while (_avpacket.size > 0);
    av_packet_unref(&orig_pkt);

    if (not success)
        return false;

    // TODO - when are there multiple passes?
    if (passes != 1)
        return false;

    frame.init_from_specs(_data_buffer[0], _data_buffer_length, _width, _height);
    return true;
}

double VideoSourceFFmpeg::get_frame_rate()
{
    int num = _avstream->avg_frame_rate.num;
    int den = _avstream->avg_frame_rate.den;
    if (num == 0)
        return 0.0;
    return static_cast<double>(num) / den;
}

void VideoSourceFFmpeg::set_sub_frame(int x, int y, int width, int height)
{
    // TODO
}

void VideoSourceFFmpeg::get_full_frame()
{
    // TODO
}

int VideoSourceFFmpeg::open_codec_context(
        int * stream_idx, AVFormatContext * fmt_ctx,
        enum AVMediaType type, std::string & error_msg)
{
    int ret, stream_index;
    AVStream * st;
    AVCodecContext * dec_ctx = nullptr;
    AVCodec * dec = nullptr;
    AVDictionary * opts = nullptr;

    ret = av_find_best_stream(fmt_ctx, type, -1, -1, nullptr, 0);
    if (ret < 0)
    {
        error_msg.append("Could not find ")
                 .append(av_get_media_type_string(type))
                 .append(" stream in source ")
                 .append(_source_path);
        return ret;
    }
    else
    {
        stream_index = ret;
        st = fmt_ctx->streams[stream_index];

        /* find decoder for the stream */
        dec_ctx = st->codec;
        dec = avcodec_find_decoder(dec_ctx->codec_id);
        if (!dec)
        {
            error_msg.append("Failed to find ")
                     .append(av_get_media_type_string(type))
                     .append(" codec");
            return AVERROR(EINVAL);
        }

        /* Init the decoders, with or without reference counting */
        av_dict_set(&opts, "refcounted_frames", _use_refcount ? "1" : "0", 0);
        if ((ret = avcodec_open2(dec_ctx, dec, &opts)) < 0)
        {
            error_msg.append("Failed to open ")
                     .append(av_get_media_type_string(type))
                     .append(" codec");
            return ret;
        }
        *stream_idx = stream_index;
    }

    return 0;
}

int VideoSourceFFmpeg::decode_packet(int * got_frame, int cached)
{
    int ret = 0;
    int decoded = _avpacket.size;
    *got_frame = 0;
    if (_avpacket.stream_index == _avstream_idx)
    {
        /* decode video frame */
        ret = avcodec_decode_video2(_avcodec_context, _avframe, got_frame, &_avpacket);
        if (ret < 0)
            return ret;

        if (*got_frame)
        {
            if (_avframe->width != _width or _avframe->height != _height or
                _avframe->format != _avpixel_format)
                return -1;
        }
    }
    /* If we use frame reference counting, we own the data and need
     * to de-reference it when we don't use it anymore */
    if (*got_frame and _use_refcount)
        av_frame_unref(_avframe);
    return decoded;
}

}
<commit_msg>Issue #74: added return value check for sws_scale<commit_after>#include "ffmpeg_video_source.h"
extern "C" {
#include <libavutil/imgutils.h>
}

namespace gg
{

VideoSourceFFmpeg::VideoSourceFFmpeg()
{
    // nop
}

VideoSourceFFmpeg::VideoSourceFFmpeg(std::string source_path,
                                     enum ColourSpace colour_space,
                                     bool use_refcount)
    : IVideoSource(colour_space)
    , _source_path(source_path)
    , _avformat_context(nullptr)
    , _avstream_idx(-1)
    , _use_refcount(use_refcount)
    , _avstream(nullptr)
    , _avcodec_context(nullptr)
    , _avframe(nullptr)
    , _avframe_converted(nullptr)
    , _sws_context(nullptr)
    , _daemon(nullptr)
{
    int ret = 0;
    std::string error_msg = "";

    av_register_all();

    if (avformat_open_input(&_avformat_context, _source_path.c_str(),
                            nullptr, nullptr) < 0)
    {
        error_msg.append("Could not open video source ")
                 .append(_source_path);
        throw VideoSourceError(error_msg);
    }

    if (avformat_find_stream_info(_avformat_context, nullptr) < 0)
        throw VideoSourceError("Could not find stream information");

    if (open_codec_context(&_avstream_idx, _avformat_context,
                           AVMEDIA_TYPE_VIDEO, error_msg) >= 0)
    {
        _avstream = _avformat_context->streams[_avstream_idx];
        _avcodec_context = _avstream->codec;

        /* allocate image where the decoded image will be put */
        _width = _avcodec_context->width;
        _height = _avcodec_context->height;
        _avpixel_format = _avcodec_context->pix_fmt;
        ret = av_image_alloc(_data_buffer, _data_buffer_linesizes,
                             _width, _height, _avpixel_format, 1);
        if (ret < 0)
            throw VideoSourceError("Could not allocate"
                                   " raw video buffer");
        _data_buffer_length = ret;
    }
    else
        throw VideoSourceError(error_msg);

    if (_avstream == nullptr)
        throw VideoSourceError("Could not find video stream in source");

    _avframe = av_frame_alloc();
    if (_avframe == nullptr)
        throw VideoSourceError("Could not allocate frame");

    /* initialize packet, set data to NULL, let the demuxer fill it */
    av_init_packet(&_avpacket);
    _avpacket.data = nullptr;
    _avpacket.size = 0;

    AVPixelFormat target_avpixel_format;
    switch(_colour)
    {
    case BGRA:
        target_avpixel_format = AV_PIX_FMT_BGRA;
        break;
    case I420:
        target_avpixel_format = AV_PIX_FMT_YUV420P;
        break;
    case UYVY:
        target_avpixel_format = AV_PIX_FMT_UYVY422;
        break;
    default:
        throw VideoSourceError("Target colour space not supported");
    }
    if (_avpixel_format != target_avpixel_format)
    {
        switch(_avpixel_format)
        {
        case AV_PIX_FMT_BGRA:
            _stride[0] = 4 * _width;
            break;
        case AV_PIX_FMT_UYVY422:
            _stride[0] = 2 * _width;
            break;
        case AV_PIX_FMT_YUV420P:
            // TODO: 1) is this correct? 2) odd width?
            _stride[0] = 1.5 * _width;
            break;
        default:
            throw VideoSourceError("Source colour space not supported");
        }
        _avframe_converted = av_frame_alloc();
        if (_avframe_converted == nullptr)
            throw VideoSourceError("Could not allocate conversion frame");
        _avframe_converted->format = target_avpixel_format;
        _avframe_converted->width  = _width;
        _avframe_converted->height = _height;
        int pixel_depth;
        switch(target_avpixel_format)
        {
        case AV_PIX_FMT_BGRA:
            pixel_depth = 32; // bits-per-pixel
            break;
        case AV_PIX_FMT_YUV420P:
            pixel_depth = 12; // bits-per-pixel
            /* TODO #54 - alignment by _pixel_depth causes problems
             * due to buffer size mismatches between EpiphanSDK and
             * FFmpeg, hence manually filling in linesizes (based on
             * debugging measurements), in conj. with
             * av_image_fill_pointers below
             */
            _avframe_converted->linesize[0] = _avframe_converted->width;
            _avframe_converted->linesize[1] = _avframe_converted->width / 2;
            _avframe_converted->linesize[2] = _avframe_converted->width / 2;
            break;
        case AV_PIX_FMT_UYVY422:
            pixel_depth = 16; // bits-per-pixel
            break;
        default:
            throw VideoSourceError("Colour space not supported");
        }
        ret = av_frame_get_buffer(_avframe_converted, pixel_depth);
        if (ret < 0)
            throw VideoSourceError("Could not allocate conversion buffer");

        _sws_context = sws_getContext(
                    _width, _height, _avpixel_format,
                    _width, _height, target_avpixel_format,
                    0, nullptr, nullptr, nullptr);
        if (_sws_context == nullptr)
            throw VideoSourceError("Could not allocate Sws context");
    }

    _daemon = new gg::BroadcastDaemon(this);
    _daemon->start(get_frame_rate());
}

VideoSourceFFmpeg::~VideoSourceFFmpeg()
{
    delete _daemon;

    if (_sws_context != nullptr)
        sws_freeContext(_sws_context);
    avcodec_close(_avcodec_context);
    avformat_close_input(&_avformat_context);
    av_frame_free(&_avframe);
    if (_avframe_converted != nullptr)
        av_frame_free(&_avframe_converted);
    av_free(_data_buffer[0]);
    _data_buffer_length = 0;
}

bool VideoSourceFFmpeg::get_frame_dimensions(int & width, int & height)
{
    if (this->_width > 0 and this->_height > 0)
    {
        width = this->_width;
        height = this->_height;
        return true;
    }
    else
        return false;
}

bool VideoSourceFFmpeg::get_frame(VideoFrame & frame)
{
    if (av_read_frame(_avformat_context, &_avpacket) < 0)
        return false;

    int ret = 0, got_frame;
    bool success = true;
    AVPacket orig_pkt = _avpacket;
    size_t passes = 0;
    do
    {
        ret = decode_packet(&got_frame, 0);
        if (ret < 0)
        {
            success = false;
            break;
        }
        _avpacket.data += ret;
        _avpacket.size -= ret;

        // need to convert pixel format?
        uint8_t ** data_ptr = nullptr;
        int * data_linesize = nullptr;
        if (_sws_context != nullptr)
        {
            ret = sws_scale(_sws_context,
                            _avframe->data, _stride,
                            0, _height,
                            _avframe_converted->data, _avframe_converted->linesize
                            );
            if (ret <= 0)
            {
                success = false;
                break;
            }
            data_ptr = _avframe_converted->data;
            data_linesize = _avframe_converted->linesize;
        }
        else
        {
            data_ptr = _avframe->data;
            data_linesize = _avframe->linesize;
        }

        /* copy decoded frame to destination buffer:
         * this is required since rawvideo expects non aligned data */
        av_image_copy(_data_buffer, _data_buffer_linesizes,
                      const_cast<const uint8_t **>(data_ptr), data_linesize,
                      _avpixel_format, _width, _height);

        passes++;
    }
    while (_avpacket.size > 0);
    av_packet_unref(&orig_pkt);

    if (not success)
        return false;

    // TODO - when are there multiple passes?
    if (passes != 1)
        return false;

    frame.init_from_specs(_data_buffer[0], _data_buffer_length, _width, _height);
    return true;
}

double VideoSourceFFmpeg::get_frame_rate()
{
    int num = _avstream->avg_frame_rate.num;
    int den = _avstream->avg_frame_rate.den;
    if (num == 0)
        return 0.0;
    return static_cast<double>(num) / den;
}

void VideoSourceFFmpeg::set_sub_frame(int x, int y, int width, int height)
{
    // TODO
}

void VideoSourceFFmpeg::get_full_frame()
{
    // TODO
}

int VideoSourceFFmpeg::open_codec_context(
        int * stream_idx, AVFormatContext * fmt_ctx,
        enum AVMediaType type, std::string & error_msg)
{
    int ret, stream_index;
    AVStream * st;
    AVCodecContext * dec_ctx = nullptr;
    AVCodec * dec = nullptr;
    AVDictionary * opts = nullptr;

    ret = av_find_best_stream(fmt_ctx, type, -1, -1, nullptr, 0);
    if (ret < 0)
    {
        error_msg.append("Could not find ")
                 .append(av_get_media_type_string(type))
                 .append(" stream in source ")
                 .append(_source_path);
        return ret;
    }
    else
    {
        stream_index = ret;
        st = fmt_ctx->streams[stream_index];

        /* find decoder for the stream */
        dec_ctx = st->codec;
        dec = avcodec_find_decoder(dec_ctx->codec_id);
        if (!dec)
        {
            error_msg.append("Failed to find ")
                     .append(av_get_media_type_string(type))
                     .append(" codec");
            return AVERROR(EINVAL);
        }

        /* Init the decoders, with or without reference counting */
        av_dict_set(&opts, "refcounted_frames", _use_refcount ? "1" : "0", 0);
        if ((ret = avcodec_open2(dec_ctx, dec, &opts)) < 0)
        {
            error_msg.append("Failed to open ")
                     .append(av_get_media_type_string(type))
                     .append(" codec");
            return ret;
        }
        *stream_idx = stream_index;
    }

    return 0;
}

int VideoSourceFFmpeg::decode_packet(int * got_frame, int cached)
{
    int ret = 0;
    int decoded = _avpacket.size;
    *got_frame = 0;
    if (_avpacket.stream_index == _avstream_idx)
    {
        /* decode video frame */
        ret = avcodec_decode_video2(_avcodec_context, _avframe, got_frame, &_avpacket);
        if (ret < 0)
            return ret;

        if (*got_frame)
        {
            if (_avframe->width != _width or _avframe->height != _height or
                _avframe->format != _avpixel_format)
                return -1;
        }
    }
    /* If we use frame reference counting, we own the data and need
     * to de-reference it when we don't use it anymore */
    if (*got_frame and _use_refcount)
        av_frame_unref(_avframe);
    return decoded;
}

}
<|endoftext|>


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

 Copyright (c) 2000-2009 Torus Knot Software Ltd

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 -----------------------------------------------------------------------------
 */
#if OGRE_PLATFORM == OGRE_PLATFORM_SYMBIAN
#	ifdef __GCCE__
#		include <staticlibinit_gcce.h>
#	endif

#	include <e32base.h> // for Symbian classes.
#	include <coemain.h> // for CCoeEnv.

#endif

#include "SampleBrowser.h"

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#elif OGRE_PLATFORM == OGRE_PLATFORM_IPHONE
#import <UIKit/UIKit.h>
#endif

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
INT WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, INT)
#else
int main(int argc, char *argv[])
#endif
{
#if OGRE_PLATFORM == OGRE_PLATFORM_IPHONE
	NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
	int retVal = UIApplicationMain(argc, argv, @"UIApplication", @"AppDelegate");
	[pool release];
	return retVal;
#else

#if OGRE_PLATFORM == OGRE_PLATFORM_SYMBIAN
    __UHEAP_MARK;

    // Create the control environment.
    CCoeEnv* environment = new (ELeave) CCoeEnv();

    TRAPD( err, environment->ConstructL( ETrue, 0 ) );

    if( err != KErrNone )
    {
        printf( "Unable to create a CCoeEnv!\n" );
        getchar();
    }

#endif

	try
	{
		OgreBites::SampleBrowser sb;
		sb.go();
	}
	catch (Ogre::Exception& e)
	{
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
		MessageBoxA(NULL, e.getFullDescription().c_str(), "An exception has occurred!", MB_ICONERROR | MB_TASKMODAL);
#else
		std::cerr << "An exception has occurred: " << e.getFullDescription().c_str() << std::endl;
#endif
#if OGRE_PLATFORM == OGRE_PLATFORM_SYMBIAN
        getchar();
#endif

	}
#if OGRE_PLATFORM == OGRE_PLATFORM_SYMBIAN
    // Close the stdout & stdin, else printf / getchar causes a memory leak.
    fclose( stdout );
    fclose( stdin );

    // Cleanup
    CCoeEnv::Static()->DestroyEnvironment();
    delete CCoeEnv::Static();

    __UHEAP_MARKEND;
#endif

#endif
	return 0;
}

#if OGRE_PLATFORM == OGRE_PLATFORM_IPHONE
#   ifdef __OBJC__
@interface AppDelegate : NSObject <UIApplicationDelegate>
{
    NSTimer *mTimer;
    OgreBites::SampleBrowser sb;
}

- (void)go;
- (void)renderOneFrame:(id)sender;

@property (retain) NSTimer *mTimer;

@end

@implementation AppDelegate

@synthesize mTimer;

- (void)go {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    try {
        sb.go();

        Ogre::Root::getSingleton().getRenderSystem()->_initRenderTargets();

        // Clear event times
		Ogre::Root::getSingleton().clearEventTimes();
    } catch( Ogre::Exception& e ) {
        std::cerr << "An exception has occurred: " <<
        e.getFullDescription().c_str() << std::endl;
    }

    mTimer = [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval)(1.0f / 60.0f)
                                              target:self
                                            selector:@selector(renderOneFrame:)
                                            userInfo:nil
                                             repeats:YES];

    [pool release];
}

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    // Hide the status bar
    [[UIApplication sharedApplication] setStatusBarHidden:YES];

    [self go];
}

- (void)renderOneFrame:(id)sender
{
    [sb.mGestureView becomeFirstResponder];

    Root::getSingleton().renderOneFrame((Real)[mTimer timeInterval]);
}

- (void)applicationWillTerminate:(UIApplication *)application {
    Ogre::Root::getSingleton().queueEndRendering();
}

//- (void)applicationWillResignActive:(UIApplication *)application
//{
//    // Pause FrameListeners and rendering
//}
//
//- (void)applicationDidBecomeActive:(UIApplication *)application
//{
//    // Resume FrameListeners and rendering
//}

- (void)dealloc {
    [mTimer release];

    [super dealloc];
}

@end
#   endif

#endif
<commit_msg>SampleBrowser.cpp needs to include OgrePlatform.h before testing OGRE_PLATFORM define.<commit_after>/*
 -----------------------------------------------------------------------------
 This source file is part of OGRE
 (Object-oriented Graphics Rendering Engine)
 For the latest info, see http://www.ogre3d.org/

 Copyright (c) 2000-2009 Torus Knot Software Ltd

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 -----------------------------------------------------------------------------
 */
#include "OgrePlatform.h"
#if OGRE_PLATFORM == OGRE_PLATFORM_SYMBIAN
#	ifdef __GCCE__
#		include <staticlibinit_gcce.h>
#	endif

#	include <e32base.h> // for Symbian classes.
#	include <coemain.h> // for CCoeEnv.

#endif

#include "SampleBrowser.h"

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#elif OGRE_PLATFORM == OGRE_PLATFORM_IPHONE
#import <UIKit/UIKit.h>
#endif

#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
INT WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, INT)
#else
int main(int argc, char *argv[])
#endif
{
#if OGRE_PLATFORM == OGRE_PLATFORM_IPHONE
	NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
	int retVal = UIApplicationMain(argc, argv, @"UIApplication", @"AppDelegate");
	[pool release];
	return retVal;
#else

#if OGRE_PLATFORM == OGRE_PLATFORM_SYMBIAN
    __UHEAP_MARK;

    // Create the control environment.
    CCoeEnv* environment = new (ELeave) CCoeEnv();

    TRAPD( err, environment->ConstructL( ETrue, 0 ) );

    if( err != KErrNone )
    {
        printf( "Unable to create a CCoeEnv!\n" );
        getchar();
    }

#endif

	try
	{
		OgreBites::SampleBrowser sb;
		sb.go();
	}
	catch (Ogre::Exception& e)
	{
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
		MessageBoxA(NULL, e.getFullDescription().c_str(), "An exception has occurred!", MB_ICONERROR | MB_TASKMODAL);
#else
		std::cerr << "An exception has occurred: " << e.getFullDescription().c_str() << std::endl;
#endif
#if OGRE_PLATFORM == OGRE_PLATFORM_SYMBIAN
        getchar();
#endif

	}
#if OGRE_PLATFORM == OGRE_PLATFORM_SYMBIAN
    // Close the stdout & stdin, else printf / getchar causes a memory leak.
    fclose( stdout );
    fclose( stdin );

    // Cleanup
    CCoeEnv::Static()->DestroyEnvironment();
    delete CCoeEnv::Static();

    __UHEAP_MARKEND;
#endif

#endif
	return 0;
}

#if OGRE_PLATFORM == OGRE_PLATFORM_IPHONE
#   ifdef __OBJC__
@interface AppDelegate : NSObject <UIApplicationDelegate>
{
    NSTimer *mTimer;
    OgreBites::SampleBrowser sb;
}

- (void)go;
- (void)renderOneFrame:(id)sender;

@property (retain) NSTimer *mTimer;

@end

@implementation AppDelegate

@synthesize mTimer;

- (void)go {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    try {
        sb.go();

        Ogre::Root::getSingleton().getRenderSystem()->_initRenderTargets();

        // Clear event times
		Ogre::Root::getSingleton().clearEventTimes();
    } catch( Ogre::Exception& e ) {
        std::cerr << "An exception has occurred: " <<
        e.getFullDescription().c_str() << std::endl;
    }

    mTimer = [NSTimer scheduledTimerWithTimeInterval:(NSTimeInterval)(1.0f / 60.0f)
                                              target:self
                                            selector:@selector(renderOneFrame:)
                                            userInfo:nil
                                             repeats:YES];

    [pool release];
}

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    // Hide the status bar
    [[UIApplication sharedApplication] setStatusBarHidden:YES];

    [self go];
}

- (void)renderOneFrame:(id)sender
{
    [sb.mGestureView becomeFirstResponder];

    Root::getSingleton().renderOneFrame((Real)[mTimer timeInterval]);
}

- (void)applicationWillTerminate:(UIApplication *)application {
    Ogre::Root::getSingleton().queueEndRendering();
}

//- (void)applicationWillResignActive:(UIApplication *)application
//{
//    // Pause FrameListeners and rendering
//}
//
//- (void)applicationDidBecomeActive:(UIApplication *)application
//{
//    // Resume FrameListeners and rendering
//}

- (void)dealloc {
    [mTimer release];

    [super dealloc];
}

@end
#   endif

#endif
<|endoftext|>


<commit_before>/*     Copyright 2015-2019 Egor Yusov
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
 *
 *  In no event and under no legal theory, whether in tort (including negligence),
 *  contract, or otherwise, unless required by applicable law (such as deliberate
 *  and grossly negligent acts) or agreed to in writing, shall any Contributor be
 *  liable for any damages, including any direct, indirect, special, incidental,
 *  or consequential damages of any character arising as a result of this License or
 *  out of the use or inability to use the software (including but not limited to damages
 *  for loss of goodwill, work stoppage, computer failure or malfunction, or any and
 *  all other commercial damages or losses), even if such Contributor has been advised
 *  of the possibility of such damages.
 */

#include "GLTFViewer.h"
#include "MapHelper.h"
#include "BasicMath.h"
#include "GraphicsUtilities.h"
#include "AntTweakBar.h"

namespace Diligent
{

#include "BasicStructures.fxh"

SampleBase* CreateSample()
{
    return new GLTFViewer();
}

void GLTFViewer::Initialize(IEngineFactory* pEngineFactory, IRenderDevice* pDevice, IDeviceContext** ppContexts, Uint32 NumDeferredCtx, ISwapChain* pSwapChain)
{
    SampleBase::Initialize(pEngineFactory, pDevice, ppContexts, NumDeferredCtx, pSwapChain);
    auto BackBufferFmt  = m_pSwapChain->GetDesc().ColorBufferFormat;
    auto DepthBufferFmt = m_pSwapChain->GetDesc().DepthBufferFormat;
    GLTF_PBR_Renderer::CreateInfo RendererCI;
    RendererCI.RTVFmt = BackBufferFmt;
    RendererCI.DSVFmt = DepthBufferFmt;
    RendererCI.AllowDebugView = true;
    m_GLTFRenderer.reset(new GLTF_PBR_Renderer(m_pDevice, m_pImmediateContext, RendererCI));

    CreateUniformBuffer(m_pDevice, sizeof(CameraAttribs), "Camera attribs buffer", &m_CameraAttribsCB);
    CreateUniformBuffer(m_pDevice, sizeof(LightAttribs),  "Light attribs buffer",  &m_LightAttribsCB);
    StateTransitionDesc Barriers [] =
    {
        {m_CameraAttribsCB, RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_CONSTANT_BUFFER, true},
        {m_LightAttribsCB,  RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_CONSTANT_BUFFER, true},
    };
    m_pImmediateContext->TransitionResourceStates(_countof(Barriers), Barriers);

    m_Model.reset(new GLTF::Model(m_pDevice, m_pImmediateContext, "models/DamagedHelmet.gltf"));
    m_GLTFRenderer->InitializeResourceBindings(*m_Model, m_CameraAttribsCB, m_LightAttribsCB);

    float3 axis(-1, 1, 0);
    m_Rotation = Quaternion::RotationFromAxisAngle(axis, PI_F/4.f);
    m_LightDirection  = normalize(float3(0.5f, -0.6f, -0.2f));

    // Create a tweak bar
    TwBar *bar = TwNewBar("Settings");
    int barSize[2] = {224 * m_UIScale, 400 * m_UIScale};
    TwSetParam(bar, NULL, "size", TW_PARAM_INT32, 2, barSize);

    TwAddVarRW(bar, "Rotation",           TW_TYPE_QUAT4F,  &m_Rotation,        "opened=true axisz=-z");
    TwAddVarRW(bar, "Light direction",    TW_TYPE_DIR3F,   &m_LightDirection,  "opened=true axisz=-z");
    TwAddVarRW(bar, "Light Color",        TW_TYPE_COLOR4F, &m_LightColor,      "opened=false");
    TwAddVarRW(bar, "Light Intensity",    TW_TYPE_FLOAT,   &m_LightIntensity,  "min=0.1 max=5.0 step=0.1");
    TwAddVarRW(bar, "Occlusion strength", TW_TYPE_FLOAT,   &m_RenderParams.OcclusionStrength, "min=0.0 max=1.0 step=0.01");
    TwAddVarRW(bar, "Emission scale",     TW_TYPE_FLOAT,   &m_RenderParams.EmissionScale,     "min=0.0 max=1.0 step=0.01");

    TwEnumVal DebugViewType[] = // array used to describe the shadow map resolution
    {
        {static_cast<int>(GLTF_PBR_Renderer::RenderInfo::DebugViewType::None),         "None"       },
        {static_cast<int>(GLTF_PBR_Renderer::RenderInfo::DebugViewType::BaseColor),    "Base Color" },
        {static_cast<int>(GLTF_PBR_Renderer::RenderInfo::DebugViewType::NormalMap),    "Normal Map" },
        {static_cast<int>(GLTF_PBR_Renderer::RenderInfo::DebugViewType::Occlusion),    "Occlusion"  },
        {static_cast<int>(GLTF_PBR_Renderer::RenderInfo::DebugViewType::Emissive),     "Emissive"   },
        {static_cast<int>(GLTF_PBR_Renderer::RenderInfo::DebugViewType::Metallic),     "Metallic"   },
        {static_cast<int>(GLTF_PBR_Renderer::RenderInfo::DebugViewType::Roughness),    "Roughness"  },
        {static_cast<int>(GLTF_PBR_Renderer::RenderInfo::DebugViewType::DiffuseColor), "Diffuse color"},
        {static_cast<int>(GLTF_PBR_Renderer::RenderInfo::DebugViewType::SpecularColor),"Specular color (R0)"},
        {static_cast<int>(GLTF_PBR_Renderer::RenderInfo::DebugViewType::Reflectance90),"Reflectance90"}
    };
    TwType DebugViewTwType = TwDefineEnum( "Debug view", DebugViewType, _countof( DebugViewType ) );
    TwAddVarRW( bar, "Debug view", DebugViewTwType, &m_RenderParams.DebugView, "" );
}

GLTFViewer::~GLTFViewer()
{
}

// Render a frame
void GLTFViewer::Render()
{
    // Clear the back buffer
    const float ClearColor[] = { 0.350f,  0.350f,  0.350f, 1.0f };
    m_pImmediateContext->ClearRenderTarget(nullptr, ClearColor, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
    m_pImmediateContext->ClearDepthStencil(nullptr, CLEAR_DEPTH_FLAG, 1.f, 0, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);

    {
        float4x4 CameraView = m_Rotation.ToMatrix() * float4x4::TranslationD3D(0.f, 0.0f, 5.0f);
        float4x4 CameraWorld = CameraView.Inverse();
        float4 CamWorld = float4(0,0,0,1) * CameraWorld;
        float3 CameraWorldPos = float3::MakeVector(CameraWorld[3]);
        float NearPlane = 0.1f;
        float FarPlane = 100.f;
        float aspectRatio = static_cast<float>(m_pSwapChain->GetDesc().Width) / static_cast<float>(m_pSwapChain->GetDesc().Height);
        // Projection matrix differs between DX and OpenGL
        auto Proj = float4x4::ProjectionD3D(PI_F / 4.f, aspectRatio, NearPlane, FarPlane, m_pDevice->GetDeviceCaps().IsGLDevice());
        // Compute world-view-projection matrix
        auto CameraViewProj = CameraView * Proj;

        {
            MapHelper<CameraAttribs> CamAttribs(m_pImmediateContext, m_CameraAttribsCB, MAP_WRITE, MAP_FLAG_DISCARD);
            CamAttribs->mViewProjT = CameraViewProj.Transpose();
            CamAttribs->f4Position = float4(CameraWorldPos, 1);
        }

        {
            MapHelper<LightAttribs> lightAttribs(m_pImmediateContext, m_LightAttribsCB, MAP_WRITE, MAP_FLAG_DISCARD);
            lightAttribs->f4Direction = m_LightDirection;
            lightAttribs->f4Intensity = m_LightColor * m_LightIntensity;
        }
    }

    m_GLTFRenderer->Render(m_pImmediateContext, *m_Model, m_RenderParams);
}

// Rotating sponge
void GLTFViewer::Update(double CurrTime, double ElapsedTime)
{
    SampleBase::Update(CurrTime, ElapsedTime);
}

}
<commit_msg>GLTF viewer: added 3 more debug modes<commit_after>/*     Copyright 2015-2019 Egor Yusov
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF ANY PROPRIETARY RIGHTS.
 *
 *  In no event and under no legal theory, whether in tort (including negligence),
 *  contract, or otherwise, unless required by applicable law (such as deliberate
 *  and grossly negligent acts) or agreed to in writing, shall any Contributor be
 *  liable for any damages, including any direct, indirect, special, incidental,
 *  or consequential damages of any character arising as a result of this License or
 *  out of the use or inability to use the software (including but not limited to damages
 *  for loss of goodwill, work stoppage, computer failure or malfunction, or any and
 *  all other commercial damages or losses), even if such Contributor has been advised
 *  of the possibility of such damages.
 */

#include "GLTFViewer.h"
#include "MapHelper.h"
#include "BasicMath.h"
#include "GraphicsUtilities.h"
#include "AntTweakBar.h"

namespace Diligent
{

#include "BasicStructures.fxh"

SampleBase* CreateSample()
{
    return new GLTFViewer();
}

void GLTFViewer::Initialize(IEngineFactory* pEngineFactory, IRenderDevice* pDevice, IDeviceContext** ppContexts, Uint32 NumDeferredCtx, ISwapChain* pSwapChain)
{
    SampleBase::Initialize(pEngineFactory, pDevice, ppContexts, NumDeferredCtx, pSwapChain);
    auto BackBufferFmt  = m_pSwapChain->GetDesc().ColorBufferFormat;
    auto DepthBufferFmt = m_pSwapChain->GetDesc().DepthBufferFormat;
    GLTF_PBR_Renderer::CreateInfo RendererCI;
    RendererCI.RTVFmt = BackBufferFmt;
    RendererCI.DSVFmt = DepthBufferFmt;
    RendererCI.AllowDebugView = true;
    m_GLTFRenderer.reset(new GLTF_PBR_Renderer(m_pDevice, m_pImmediateContext, RendererCI));

    CreateUniformBuffer(m_pDevice, sizeof(CameraAttribs), "Camera attribs buffer", &m_CameraAttribsCB);
    CreateUniformBuffer(m_pDevice, sizeof(LightAttribs),  "Light attribs buffer",  &m_LightAttribsCB);
    StateTransitionDesc Barriers [] =
    {
        {m_CameraAttribsCB, RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_CONSTANT_BUFFER, true},
        {m_LightAttribsCB,  RESOURCE_STATE_UNKNOWN, RESOURCE_STATE_CONSTANT_BUFFER, true},
    };
    m_pImmediateContext->TransitionResourceStates(_countof(Barriers), Barriers);

    m_Model.reset(new GLTF::Model(m_pDevice, m_pImmediateContext, "models/DamagedHelmet.gltf"));
    m_GLTFRenderer->InitializeResourceBindings(*m_Model, m_CameraAttribsCB, m_LightAttribsCB);

    float3 axis(-1, 1, 0);
    m_Rotation = Quaternion::RotationFromAxisAngle(axis, PI_F/4.f);
    m_LightDirection  = normalize(float3(0.5f, -0.6f, -0.2f));

    // Create a tweak bar
    TwBar *bar = TwNewBar("Settings");
    int barSize[2] = {224 * m_UIScale, 400 * m_UIScale};
    TwSetParam(bar, NULL, "size", TW_PARAM_INT32, 2, barSize);

    TwAddVarRW(bar, "Rotation",           TW_TYPE_QUAT4F,  &m_Rotation,        "opened=true axisz=-z");
    TwAddVarRW(bar, "Light direction",    TW_TYPE_DIR3F,   &m_LightDirection,  "opened=true axisz=-z");
    TwAddVarRW(bar, "Light Color",        TW_TYPE_COLOR4F, &m_LightColor,      "opened=false");
    TwAddVarRW(bar, "Light Intensity",    TW_TYPE_FLOAT,   &m_LightIntensity,  "min=0.1 max=5.0 step=0.1");
    TwAddVarRW(bar, "Occlusion strength", TW_TYPE_FLOAT,   &m_RenderParams.OcclusionStrength, "min=0.0 max=1.0 step=0.01");
    TwAddVarRW(bar, "Emission scale",     TW_TYPE_FLOAT,   &m_RenderParams.EmissionScale,     "min=0.0 max=1.0 step=0.01");

    TwEnumVal DebugViewType[] = // array used to describe the shadow map resolution
    {
        {static_cast<int>(GLTF_PBR_Renderer::RenderInfo::DebugViewType::None),            "None"       },
        {static_cast<int>(GLTF_PBR_Renderer::RenderInfo::DebugViewType::BaseColor),       "Base Color" },
        {static_cast<int>(GLTF_PBR_Renderer::RenderInfo::DebugViewType::NormalMap),       "Normal Map" },
        {static_cast<int>(GLTF_PBR_Renderer::RenderInfo::DebugViewType::Occlusion),       "Occlusion"  },
        {static_cast<int>(GLTF_PBR_Renderer::RenderInfo::DebugViewType::Emissive),        "Emissive"   },
        {static_cast<int>(GLTF_PBR_Renderer::RenderInfo::DebugViewType::Metallic),        "Metallic"   },
        {static_cast<int>(GLTF_PBR_Renderer::RenderInfo::DebugViewType::Roughness),       "Roughness"  },
        {static_cast<int>(GLTF_PBR_Renderer::RenderInfo::DebugViewType::DiffuseColor),    "Diffuse color"},
        {static_cast<int>(GLTF_PBR_Renderer::RenderInfo::DebugViewType::SpecularColor),   "Specular color (R0)"},
        {static_cast<int>(GLTF_PBR_Renderer::RenderInfo::DebugViewType::Reflectance90),   "Reflectance90"},
        {static_cast<int>(GLTF_PBR_Renderer::RenderInfo::DebugViewType::MeshNormal),      "Mesh normal"},
        {static_cast<int>(GLTF_PBR_Renderer::RenderInfo::DebugViewType::PerturbedNormal), "Perturbed normal"},
        {static_cast<int>(GLTF_PBR_Renderer::RenderInfo::DebugViewType::NdotV),           "n*v"}
    };
    TwType DebugViewTwType = TwDefineEnum( "Debug view", DebugViewType, _countof( DebugViewType ) );
    TwAddVarRW( bar, "Debug view", DebugViewTwType, &m_RenderParams.DebugView, "" );
}

GLTFViewer::~GLTFViewer()
{
}

// Render a frame
void GLTFViewer::Render()
{
    // Clear the back buffer
    const float ClearColor[] = { 0.350f,  0.350f,  0.350f, 1.0f };
    m_pImmediateContext->ClearRenderTarget(nullptr, ClearColor, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);
    m_pImmediateContext->ClearDepthStencil(nullptr, CLEAR_DEPTH_FLAG, 1.f, 0, RESOURCE_STATE_TRANSITION_MODE_TRANSITION);

    {
        float4x4 CameraView = m_Rotation.ToMatrix() * float4x4::TranslationD3D(0.f, 0.0f, 5.0f);
        float4x4 CameraWorld = CameraView.Inverse();
        float4 CamWorld = float4(0,0,0,1) * CameraWorld;
        float3 CameraWorldPos = float3::MakeVector(CameraWorld[3]);
        float NearPlane = 0.1f;
        float FarPlane = 100.f;
        float aspectRatio = static_cast<float>(m_pSwapChain->GetDesc().Width) / static_cast<float>(m_pSwapChain->GetDesc().Height);
        // Projection matrix differs between DX and OpenGL
        auto Proj = float4x4::ProjectionD3D(PI_F / 4.f, aspectRatio, NearPlane, FarPlane, m_pDevice->GetDeviceCaps().IsGLDevice());
        // Compute world-view-projection matrix
        auto CameraViewProj = CameraView * Proj;

        {
            MapHelper<CameraAttribs> CamAttribs(m_pImmediateContext, m_CameraAttribsCB, MAP_WRITE, MAP_FLAG_DISCARD);
            CamAttribs->mViewProjT = CameraViewProj.Transpose();
            CamAttribs->f4Position = float4(CameraWorldPos, 1);
        }

        {
            MapHelper<LightAttribs> lightAttribs(m_pImmediateContext, m_LightAttribsCB, MAP_WRITE, MAP_FLAG_DISCARD);
            lightAttribs->f4Direction = m_LightDirection;
            lightAttribs->f4Intensity = m_LightColor * m_LightIntensity;
        }
    }

    m_GLTFRenderer->Render(m_pImmediateContext, *m_Model, m_RenderParams);
}

// Rotating sponge
void GLTFViewer::Update(double CurrTime, double ElapsedTime)
{
    SampleBase::Update(CurrTime, ElapsedTime);
}

}
<|endoftext|>


<commit_before>/*
 * The MIT License
 *
 * Copyright 2017-2018 Norwegian University of Technology
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING  FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <utility>

#include "ModelExchangeSlave.cpp"
#include <fmi4cpp/fmi2/import/Solver.hpp>

using namespace fmi4cpp::fmi2;

OdeintRK4::OdeintRK4(double stepSize) : stepSize(stepSize) {
    rk4 = runge_kutta4_classic<std::vector<double>>();
}

void OdeintRK4::integrate(ModelExchangeSlave &slave, double t0, std::vector<double> &x0, double t) {
    integrate_const(rk4, std::ref(slave), x0, t0, t, (t-t0));
}

<commit_msg>update<commit_after>/*
 * The MIT License
 *
 * Copyright 2017-2018 Norwegian University of Technology
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING  FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <utility>

#include <fmi4cpp/fmi2/import/ModelExchangeSlave.hpp>
#include <fmi4cpp/fmi2/import/Solver.hpp>

using namespace fmi4cpp::fmi2;

OdeintRK4::OdeintRK4(double stepSize) : stepSize(stepSize) {
    rk4 = runge_kutta4_classic<std::vector<double>>();
}

void OdeintRK4::integrate(ModelExchangeSlave &slave, double t0, std::vector<double> &x0, double t) {
    integrate_const(rk4, std::ref(slave), x0, t0, t, (t-t0));
}

<|endoftext|>


<commit_before>#include "x_client_name.hpp"

#include <xcb/xcb_ewmh.h>
#include <xcb/xcb_icccm.h>

x_client_name::x_client_name(x_connection & c,
                             generic::config_t & config,
                             x_client & x_client,
                             XVisualInfo * const visual_info,
                             const Colormap & colormap)
  : m_c(c), m_config(config), m_x_client(x_client),
    m_visual_info(visual_info), m_colormap(colormap)
{
  m_c.attach(10, XCB_PROPERTY_NOTIFY, this);
  m_c.update_input(m_x_client.window(), XCB_EVENT_MASK_PROPERTY_CHANGE);

  m_config.attach(this);
  m_x_client.attach(this);

  load_config();

  update_wm_name();
  update_wm_class();
  update_net_wm_name();
}

x_client_name::~x_client_name(void)
{
  m_c.detach(XCB_PROPERTY_NOTIFY, this);
  m_config.detach(this);
  m_x_client.detach(this);
}

const std::string & x_client_name::net_wm_name(void) const
{
  return m_net_wm_name;
}

const std::string & x_client_name::wm_name(void) const
{
  return m_wm_name;
}

const std::string & x_client_name::wm_class_name(void) const
{
  return m_class_name;
}

const std::string & x_client_name::wm_instance_name(void) const
{
  return m_instance_name;
}

xcb_pixmap_t
x_client_name::title(void) const
{
  return m_xft->drawable();
}

bool
x_client_name::handle(xcb_generic_event_t * ge)
{
  bool result = false;
  bool update_title = false;

  if (XCB_PROPERTY_NOTIFY == (ge->response_type & ~0x80)) {
    xcb_property_notify_event_t * e = (xcb_property_notify_event_t *)ge;

    if (e->window != m_x_client.window()) result = true;

    if (e->atom == m_a_wm_name) {
      update_title = true;
      update_wm_name();

    } else if (e->atom == m_a_wm_class) {
      update_title = true;
      update_wm_class();

    } else if (e->atom == m_a_net_wm_name) {
      update_title = true;
      update_net_wm_name();

    }

    result = true;
  }

  // TODO: cause clang to crash, FILE A BUG REPORT
#if defined  __GNUC__
  if (update_title) {
    observable::notify();
  }
#else
#error "Fix compilation with anything else but GNUC"
#endif

  return result;
}

void
x_client_name::notify(generic::config_t *)
{
  load_config();
  // TODO: cause clang to crash, FILE A BUG REPORT
#if defined  __GNUC__
  observable::notify();
#else
#error "Fix compilation with anything else but GNUC"
#endif
}

void
x_client_name::notify(x_client *)
{
  // TODO: cause clang to crash, FILE A BUG REPORT
#if defined  __GNUC__
  observable::notify();
#else
#error "Fix compilation with anything else but GNUC"
#endif
}

// private

void
x_client_name::load_config(void)
{
  m_icon_size    = m_config["iconsize"].v.num;
  m_border_width = m_config["borderwidth"].v.num;

  m_pnamefont    = *m_config["titlefont"].v.str;
  m_titlefont    = *m_config["subtitlefont"].v.str;

  m_bg_alpha     = m_config["titlebgalpha"].v.dbl;
  m_fg_color     = *m_config["titlefgcolor"].v.str;
  m_bg_color     = *m_config["titlebgcolor"].v.str;
}

void
x_client_name::update_net_wm_name(void)
{
  m_net_wm_name.clear();

  xcb_generic_error_t * error;
  xcb_get_property_cookie_t c =
    xcb_ewmh_get_wm_name(m_c.ewmh(), m_x_client.window());
  xcb_get_property_reply_t * r = xcb_get_property_reply(m_c(), c, &error);

  if (error) {
    delete error;

  } else {
    xcb_ewmh_get_utf8_strings_reply_t net_wm_name;
    if (xcb_ewmh_get_wm_name_from_reply(m_c.ewmh(), &net_wm_name, r)) {
      m_net_wm_name = std::string(net_wm_name.strings, net_wm_name.strings_len);
      xcb_ewmh_get_utf8_strings_reply_wipe(&net_wm_name);
      r = NULL;
    }
  }

  if (r) delete r;
}

void
x_client_name::update_wm_name(void)
{
  m_wm_name.clear();

  xcb_generic_error_t * error;
  xcb_icccm_get_text_property_reply_t wm_name;
  xcb_get_property_cookie_t c =
    xcb_icccm_get_wm_name(m_c(), m_x_client.window());
  xcb_icccm_get_wm_name_reply(m_c(), c, &wm_name, &error);

  // TODO: cause clang to crash, FILE A BUG REPORT
#if defined  __GNUC__
  if (error) {
    delete error;

  } else {
    m_wm_name = std::string(wm_name.name, wm_name.name_len);
    xcb_icccm_get_text_property_reply_wipe(&wm_name);
  }

#else
#error "Fix compilation with anything else but GNUC"
#endif
}

void
x_client_name::update_wm_class(void)
{
  m_class_name.clear();
  m_instance_name.clear();

  xcb_generic_error_t * error;
  xcb_get_property_cookie_t c =
    xcb_icccm_get_wm_class(m_c(), m_x_client.window());
  xcb_get_property_reply_t * r = xcb_get_property_reply(m_c(), c, &error);

  if (error) {
    delete error;

  } else {
    xcb_icccm_get_wm_class_reply_t wm_class;
    if (xcb_icccm_get_wm_class_from_reply(&wm_class, r)) {
      m_class_name = wm_class.class_name;
      m_instance_name = wm_class.instance_name;
      xcb_icccm_get_wm_class_reply_wipe(&wm_class);
      r = NULL;
    }
  }

  if (r) delete r;
}

x_client_name &
x_client_name::make_title(void)
{
  if (m_reset_xft) {
    m_reset_xft = false;
    m_xft = std::shared_ptr<x::xft>(new x::xft(
          m_c.dpy(), m_visual_info, m_colormap, m_title_width, m_title_height));
  }

  m_xft->foreground(m_fg_color)
        .background(m_bg_color)
        .bg_alpha(m_bg_alpha)
        .fill();

  std::string pname = m_class_name;
  std::string title = m_net_wm_name.empty() ? m_wm_name : m_net_wm_name;

  std::string lower = "abcdefghijklmnopqrstuvwxy";
  std::string upper = "ABCDEFGHIJKLMNOPQRSTUVWXY";

  XGlyphInfo text_extents = m_xft->text_extents_utf8(m_pnamefont, lower + upper);

  int x_off = m_icon_size + 4 * m_border_width;
  int y_off = m_border_width;

  y_off += text_extents.height;
  m_xft->font(m_pnamefont).draw_string_utf8(pname, x_off, y_off);

  y_off += text_extents.height;
  m_xft->font(m_titlefont).draw_string_utf8(title, x_off, y_off);

  return *this;
}
<commit_msg>Fix subtle free/invalid pointer segfaults<commit_after>#include "x_client_name.hpp"

#include <xcb/xcb_ewmh.h>
#include <xcb/xcb_icccm.h>

x_client_name::x_client_name(x_connection & c,
                             generic::config_t & config,
                             x_client & x_client,
                             XVisualInfo * const visual_info,
                             const Colormap & colormap)
  : m_c(c), m_config(config), m_x_client(x_client),
    m_visual_info(visual_info), m_colormap(colormap)
{
  m_c.attach(10, XCB_PROPERTY_NOTIFY, this);
  m_c.update_input(m_x_client.window(), XCB_EVENT_MASK_PROPERTY_CHANGE);

  m_config.attach(this);
  m_x_client.attach(this);

  load_config();

  update_wm_name();
  update_wm_class();
  update_net_wm_name();
}

x_client_name::~x_client_name(void)
{
  m_c.detach(XCB_PROPERTY_NOTIFY, this);
  m_config.detach(this);
  m_x_client.detach(this);
}

const std::string & x_client_name::net_wm_name(void) const
{
  return m_net_wm_name;
}

const std::string & x_client_name::wm_name(void) const
{
  return m_wm_name;
}

const std::string & x_client_name::wm_class_name(void) const
{
  return m_class_name;
}

const std::string & x_client_name::wm_instance_name(void) const
{
  return m_instance_name;
}

xcb_pixmap_t
x_client_name::title(void) const
{
  return m_xft->drawable();
}

bool
x_client_name::handle(xcb_generic_event_t * ge)
{
  bool result = false;
  bool update_title = false;

  if (XCB_PROPERTY_NOTIFY == (ge->response_type & ~0x80)) {
    xcb_property_notify_event_t * e = (xcb_property_notify_event_t *)ge;

    if (e->window != m_x_client.window()) result = true;

    if (e->atom == m_a_wm_name) {
      update_title = true;
      update_wm_name();

    } else if (e->atom == m_a_wm_class) {
      update_title = true;
      update_wm_class();

    } else if (e->atom == m_a_net_wm_name) {
      update_title = true;
      update_net_wm_name();

    }

    result = true;
  }

  // TODO: cause clang to crash, FILE A BUG REPORT
#if defined  __GNUC__
  if (update_title) {
    observable::notify();
  }
#else
#error "Fix compilation with anything else but GNUC"
#endif

  return result;
}

void
x_client_name::notify(generic::config_t *)
{
  load_config();
  // TODO: cause clang to crash, FILE A BUG REPORT
#if defined  __GNUC__
  observable::notify();
#else
#error "Fix compilation with anything else but GNUC"
#endif
}

void
x_client_name::notify(x_client *)
{
  // TODO: cause clang to crash, FILE A BUG REPORT
#if defined  __GNUC__
  observable::notify();
#else
#error "Fix compilation with anything else but GNUC"
#endif
}

// private

void
x_client_name::load_config(void)
{
  m_icon_size    = m_config["iconsize"].v.num;
  m_border_width = m_config["borderwidth"].v.num;

  m_pnamefont    = *m_config["titlefont"].v.str;
  m_titlefont    = *m_config["subtitlefont"].v.str;

  m_bg_alpha     = m_config["titlebgalpha"].v.dbl;
  m_fg_color     = *m_config["titlefgcolor"].v.str;
  m_bg_color     = *m_config["titlebgcolor"].v.str;
}

void
x_client_name::update_net_wm_name(void)
{
  m_net_wm_name.clear();

  xcb_generic_error_t * error;
  xcb_get_property_cookie_t c =
    xcb_ewmh_get_wm_name(m_c.ewmh(), m_x_client.window());
  xcb_get_property_reply_t * r = xcb_get_property_reply(m_c(), c, &error);

  if (error) {
    delete error;

  } else {
    xcb_ewmh_get_utf8_strings_reply_t net_wm_name;
    if (xcb_ewmh_get_wm_name_from_reply(m_c.ewmh(), &net_wm_name, r)) {
      m_net_wm_name = std::string(net_wm_name.strings, net_wm_name.strings_len);
      xcb_ewmh_get_utf8_strings_reply_wipe(&net_wm_name);
      r = NULL;
    }
  }

  if (r) delete r;
}

void
x_client_name::update_wm_name(void)
{
  m_wm_name.clear();

  std::shared_ptr<xcb_icccm_get_text_property_reply_t>
    wm_name(
        reinterpret_cast<xcb_icccm_get_text_property_reply_t *>(
          std::calloc(1, sizeof(xcb_icccm_get_text_property_reply_t))),
        [](xcb_icccm_get_text_property_reply_t * r)
        {
          xcb_icccm_get_text_property_reply_wipe(r);
        });

  xcb_get_property_cookie_t c =
    xcb_icccm_get_wm_name_unchecked(m_c(), m_x_client.window());

  xcb_generic_error_t * error = NULL;
  bool success = xcb_icccm_get_wm_name_reply(m_c(), c, wm_name.get(), &error);

  // TODO: cause clang to crash, FILE A BUG REPORT
#if defined  __GNUC__
  if (error) {
    std::free(error);

  } else if (success) {
    m_wm_name = std::string(wm_name->name);
  }

#else
#error "Fix compilation with anything else but GNUC"
#endif
}

void
x_client_name::update_wm_class(void)
{
  m_class_name.clear();
  m_instance_name.clear();

  xcb_generic_error_t * error = NULL;
  xcb_get_property_cookie_t c =
    xcb_icccm_get_wm_class_unchecked(m_c(), m_x_client.window());
  xcb_get_property_reply_t * r = xcb_get_property_reply(m_c(), c, &error);

  if (error) {
    delete error;

  } else if (r) {
    xcb_icccm_get_wm_class_reply_t wm_class;
    if (xcb_icccm_get_wm_class_from_reply(&wm_class, r)) {
      m_class_name = std::string(wm_class.class_name);
      m_instance_name = std::string(wm_class.instance_name);
      xcb_icccm_get_wm_class_reply_wipe(&wm_class);
    } else {
      std::free(r);
    }
  }
}

x_client_name &
x_client_name::make_title(void)
{
  if (m_reset_xft) {
    m_reset_xft = false;
    m_xft = std::shared_ptr<x::xft>(new x::xft(
          m_c.dpy(), m_visual_info, m_colormap, m_title_width, m_title_height));
  }

  m_xft->foreground(m_fg_color)
        .background(m_bg_color)
        .bg_alpha(m_bg_alpha)
        .fill();

  std::string pname = m_class_name;
  std::string title = m_net_wm_name.empty() ? m_wm_name : m_net_wm_name;

  std::string lower = "abcdefghijklmnopqrstuvwxy";
  std::string upper = "ABCDEFGHIJKLMNOPQRSTUVWXY";

  XGlyphInfo text_extents = m_xft->text_extents_utf8(m_pnamefont, lower + upper);

  int x_off = m_icon_size + 4 * m_border_width;
  int y_off = m_border_width;

  y_off += text_extents.height;
  m_xft->font(m_pnamefont).draw_string_utf8(pname, x_off, y_off);

  y_off += text_extents.height;
  m_xft->font(m_titlefont).draw_string_utf8(title, x_off, y_off);

  return *this;
}
<|endoftext|>


<commit_before>// 01.01.2017 Султан Xottab_DUTY Урамаев
// Чем стрелы коленом ловить, гораздо интереснее отстреливать свои ноги. Продолжим.
#include "pch.hpp"

#include <iostream>
#include <thread>

#include <GLFW/glfw3.h>
#include "dynlib/Dynlib.hpp"

#include "Common/Platform.hpp"
#include "xdCore/Log.hpp"
#include "xdCore/xdCore.hpp"
#include "Console/Console.hpp"
#include "xdEngine.hpp"

void watch_console()
{
#ifdef DEBUG
    const bool allowed = true;
#else
    const bool allowed = Core.FindParam(XDay::eParamDontHideSystemConsole);
#endif

    while (allowed && !glfwWindowShouldClose(Engine.windowMain))
    {
        std::string input;
        std::getline(std::cin, input);
        if (!glfwWindowShouldClose(Engine.windowMain))
            Console.Execute(input);
        else
            break;
    }
}

void AttachRenderer()
{
    const auto handle = Dynlib::open(Core.GetModuleName(XDay::eRendererModule).c_str());

    const auto func = (FunctionPointer)Dynlib::load(handle, "InitializeRenderer");
    if (func)
        func();
    else
        Error("Cannot attach function InitializeRenderer from {}", Core.GetModuleName(XDay::eRendererModule));
    Dynlib::close(handle);
}

int main(int argc, char* argv[])
{
    Core.InitializeArguments(argc, argv);

#ifdef WINDOWS
    SetConsoleCP(65001);
    SetConsoleOutputCP(65001);
    if (!Core.FindParam(XDay::eParamDontHideSystemConsole))
        FreeConsole();
#endif

    Core.Initialize();
    Console.Initialize();

    DebugMsg(Core.GetGLFWVersionString());
    Info(Core.GetBuildString());
    Info("Core.Params: " + Core.ParamsString);
    Info("Девиз: Чем стрелы коленом ловить, гораздо интереснее отстреливать свои ноги. Продолжим.");
    Info("Slogan: It's more interesting to shoot your feet, than catch arrows by your knee. Let's continue.");
    Core.GetParamsHelp();

    Console.ExecuteConfig();
    ErrorIf(!glfwInit(), "GLFW not initialized.");

    AttachRenderer();

    Engine.Initialize();
    Engine.createMainWindow();

    std::thread WatchConsole(watch_console);

    Engine.InitRender();

    Engine.mainLoop();

    WatchConsole.~thread();

    glfwTerminate();

    return 0;
}
<commit_msg>Do not close dll handle!<commit_after>// 01.01.2017 Султан Xottab_DUTY Урамаев
// Чем стрелы коленом ловить, гораздо интереснее отстреливать свои ноги. Продолжим.
#include "pch.hpp"

#include <iostream>
#include <thread>

#include <GLFW/glfw3.h>
#include "dynlib/Dynlib.hpp"

#include "Common/Platform.hpp"
#include "xdCore/Log.hpp"
#include "xdCore/xdCore.hpp"
#include "Console/Console.hpp"
#include "xdEngine.hpp"

void watch_console()
{
#ifdef DEBUG
    const bool allowed = true;
#else
    const bool allowed = Core.FindParam(XDay::eParamDontHideSystemConsole);
#endif

    while (allowed && !glfwWindowShouldClose(Engine.windowMain))
    {
        std::string input;
        std::getline(std::cin, input);
        if (!glfwWindowShouldClose(Engine.windowMain))
            Console.Execute(input);
        else
            break;
    }
}

void AttachRenderer()
{
    const auto handle = Dynlib::open(Core.GetModuleName(XDay::eRendererModule).c_str());

    const auto func = (FunctionPointer)Dynlib::load(handle, "InitializeRenderer");
    if (func)
        func();
    else
        Error("Cannot attach function InitializeRenderer from {}", Core.GetModuleName(XDay::eRendererModule));
    //Dynlib::close(handle);
}

int main(int argc, char* argv[])
{
    Core.InitializeArguments(argc, argv);

#ifdef WINDOWS
    SetConsoleCP(65001);
    SetConsoleOutputCP(65001);
    if (!Core.FindParam(XDay::eParamDontHideSystemConsole))
        FreeConsole();
#endif

    Core.Initialize();
    Console.Initialize();

    DebugMsg(Core.GetGLFWVersionString());
    Info(Core.GetBuildString());
    Info("Core.Params: " + Core.ParamsString);
    Info("Девиз: Чем стрелы коленом ловить, гораздо интереснее отстреливать свои ноги. Продолжим.");
    Info("Slogan: It's more interesting to shoot your feet, than catch arrows by your knee. Let's continue.");
    Core.GetParamsHelp();

    Console.ExecuteConfig();
    ErrorIf(!glfwInit(), "GLFW not initialized.");

    AttachRenderer();

    Engine.Initialize();
    Engine.createMainWindow();

    std::thread WatchConsole(watch_console);

    Engine.InitRender();

    Engine.mainLoop();

    WatchConsole.~thread();

    glfwTerminate();

    return 0;
}
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "stateseditorwidget.h"
#include "stateseditormodel.h"
#include "stateseditorview.h"

#include <qmlitemnode.h>
#include <invalidargumentexception.h>
#include <invalidqmlsourceexception.h>

#include <QtCore/QFile>
#include <qapplication.h>

#include <QtGui/QBoxLayout>
#include <QtGui/QListWidget>
#include <QtGui/QPushButton>
#include <QtGui/QMessageBox>

#include <QtDeclarative/QDeclarativeView>
#include <QtDeclarative/QDeclarativeContext>
#include <QtDeclarative/QDeclarativeEngine>
#include <QtDeclarative/QDeclarativeItem>

enum {
    debug = false
};

namespace QmlDesigner {

namespace Internal {

class StatesEditorWidgetPrivate : QObject
{
    Q_OBJECT

private:
    StatesEditorWidgetPrivate(StatesEditorWidget *q);

    int currentIndex() const;
    void setCurrentIndex(int i);

    bool validStateName(const QString &name) const;

private slots:
    void currentStateChanged();
    void addState();
    void removeState(int);
    void duplicateCurrentState();

private:
    StatesEditorWidget *m_q;
    QWeakPointer<Model> model;
    QWeakPointer<QDeclarativeView> listView;
    QWeakPointer<Internal::StatesEditorModel> statesEditorModel;
    QWeakPointer<Internal::StatesEditorView> statesEditorView;
    friend class QmlDesigner::StatesEditorWidget;
};

StatesEditorWidgetPrivate::StatesEditorWidgetPrivate(StatesEditorWidget *q) :
        QObject(q),
        m_q(q)
{
}

int StatesEditorWidgetPrivate::currentIndex() const
{
    Q_ASSERT(listView->rootObject());
    Q_ASSERT(listView->rootObject()->property("currentStateIndex").isValid());
    return listView->rootObject()->property("currentStateIndex").toInt();
}

void StatesEditorWidgetPrivate::setCurrentIndex(int i)
{
    listView->rootObject()->setProperty("currentStateIndex", i);
}

bool StatesEditorWidgetPrivate::validStateName(const QString &name) const
{
    if (name == tr("base state"))
        return false;
    QList<QmlModelState> modelStates = statesEditorView->stateRootNode().states().allStates();
    foreach (const QmlModelState &state, modelStates) {
        if (state.name() == name)
            return false;
    }
    return true;
}

void StatesEditorWidgetPrivate::currentStateChanged()
{
    statesEditorView->setCurrentState(currentIndex());
}

void StatesEditorWidgetPrivate::addState()
{
    // can happen when root node is e.g. a ListModel
    if (!statesEditorView->stateRootNode().isValid())
        return;

    QStringList modelStateNames = statesEditorView->stateRootNode().states().names();

    QString newStateName;
    int index = 1;
    while (1) {
        newStateName = tr("State%1").arg(index++);
        if (!modelStateNames.contains(newStateName))
            break;
    }
    statesEditorView->createState(newStateName);
}

void StatesEditorWidgetPrivate::removeState(int i)
{
    statesEditorView->removeState(i);
}

void StatesEditorWidgetPrivate::duplicateCurrentState()
{
    statesEditorView->duplicateCurrentState(currentIndex());
}

} // namespace Internal

StatesEditorWidget::StatesEditorWidget(QWidget *parent):
        QWidget(parent),
        m_d(new Internal::StatesEditorWidgetPrivate(this))
{
    m_d->statesEditorModel = new Internal::StatesEditorModel(this);
    m_d->listView = new QDeclarativeView(this);

    m_d->listView->setAcceptDrops(false);

    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->setMargin(0);
    layout->setSpacing(0);
    layout->addWidget(m_d->listView.data());

    m_d->listView->setResizeMode(QDeclarativeView::SizeRootObjectToView);

    m_d->listView->rootContext()->setContextProperty(QLatin1String("statesEditorModel"), m_d->statesEditorModel.data());

    m_d->listView->setSource(QUrl("qrc:/stateseditor/stateslist.qml"));

    if (!m_d->listView->rootObject())
        throw InvalidQmlSourceException(__LINE__, __FUNCTION__, __FILE__);

    m_d->listView->setFocusPolicy(Qt::ClickFocus);
    QApplication::sendEvent(m_d->listView->scene(), new QEvent(QEvent::WindowActivate));

    connect(m_d->listView->rootObject(), SIGNAL(currentStateIndexChanged()), m_d, SLOT(currentStateChanged()));
    connect(m_d->listView->rootObject(), SIGNAL(createNewState()), m_d, SLOT(addState()));
    connect(m_d->listView->rootObject(), SIGNAL(duplicateCurrentState()), m_d, SLOT(duplicateCurrentState()));
    connect(m_d->listView->rootObject(), SIGNAL(deleteState(int)), m_d, SLOT(removeState(int)));

    setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred));

    setWindowTitle(tr("States", "Title of Editor widget"));
}

StatesEditorWidget::~StatesEditorWidget()
{
    delete m_d;
}

void StatesEditorWidget::setup(Model *model)
{
    m_d->model = model;
    if (m_d->statesEditorView.isNull())
        m_d->statesEditorView = new Internal::StatesEditorView(m_d->statesEditorModel.data(), this);
    m_d->statesEditorModel->setStatesEditorView(m_d->statesEditorView.data());

    m_d->model->attachView(m_d->statesEditorView.data());

    // select first state (which is the base state)
    m_d->currentStateChanged();
}

QSize StatesEditorWidget::sizeHint() const
{
    return QSize(9999, 159);
}

}

#include "stateseditorwidget.moc"
<commit_msg>QmlDesigner: Fix crash when opening a .qml file with states<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "stateseditorwidget.h"
#include "stateseditormodel.h"
#include "stateseditorview.h"

#include <qmlitemnode.h>
#include <invalidargumentexception.h>
#include <invalidqmlsourceexception.h>

#include <QtCore/QFile>
#include <qapplication.h>

#include <QtGui/QBoxLayout>
#include <QtGui/QListWidget>
#include <QtGui/QPushButton>
#include <QtGui/QMessageBox>

#include <QtDeclarative/QDeclarativeView>
#include <QtDeclarative/QDeclarativeContext>
#include <QtDeclarative/QDeclarativeEngine>
#include <QtDeclarative/QDeclarativeItem>

enum {
    debug = false
};

namespace QmlDesigner {

namespace Internal {

class StatesEditorWidgetPrivate : QObject
{
    Q_OBJECT

private:
    StatesEditorWidgetPrivate(StatesEditorWidget *q);

    int currentIndex() const;
    void setCurrentIndex(int i);

    bool validStateName(const QString &name) const;

private slots:
    void currentStateChanged();
    void addState();
    void removeState(int);
    void duplicateCurrentState();

private:
    StatesEditorWidget *m_q;
    QWeakPointer<Model> model;
    QWeakPointer<QDeclarativeView> listView;
    QWeakPointer<Internal::StatesEditorModel> statesEditorModel;
    QWeakPointer<Internal::StatesEditorView> statesEditorView;
    friend class QmlDesigner::StatesEditorWidget;
};

StatesEditorWidgetPrivate::StatesEditorWidgetPrivate(StatesEditorWidget *q) :
        QObject(q),
        m_q(q)
{
}

int StatesEditorWidgetPrivate::currentIndex() const
{
    Q_ASSERT(listView->rootObject());
    Q_ASSERT(listView->rootObject()->property("currentStateIndex").isValid());
    return listView->rootObject()->property("currentStateIndex").toInt();
}

void StatesEditorWidgetPrivate::setCurrentIndex(int i)
{
    listView->rootObject()->setProperty("currentStateIndex", i);
}

bool StatesEditorWidgetPrivate::validStateName(const QString &name) const
{
    if (name == tr("base state"))
        return false;
    QList<QmlModelState> modelStates = statesEditorView->stateRootNode().states().allStates();
    foreach (const QmlModelState &state, modelStates) {
        if (state.name() == name)
            return false;
    }
    return true;
}

void StatesEditorWidgetPrivate::currentStateChanged()
{
    statesEditorView->setCurrentState(currentIndex());
}

void StatesEditorWidgetPrivate::addState()
{
    // can happen when root node is e.g. a ListModel
    if (!statesEditorView->stateRootNode().isValid())
        return;

    QStringList modelStateNames = statesEditorView->stateRootNode().states().names();

    QString newStateName;
    int index = 1;
    while (1) {
        newStateName = tr("State%1").arg(index++);
        if (!modelStateNames.contains(newStateName))
            break;
    }
    statesEditorView->createState(newStateName);
}

void StatesEditorWidgetPrivate::removeState(int i)
{
    statesEditorView->removeState(i);
}

void StatesEditorWidgetPrivate::duplicateCurrentState()
{
    statesEditorView->duplicateCurrentState(currentIndex());
}

} // namespace Internal

StatesEditorWidget::StatesEditorWidget(QWidget *parent):
        QWidget(parent),
        m_d(new Internal::StatesEditorWidgetPrivate(this))
{
    m_d->statesEditorModel = new Internal::StatesEditorModel(this);
    m_d->listView = new QDeclarativeView(this);

    m_d->listView->setAcceptDrops(false);

    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->setMargin(0);
    layout->setSpacing(0);
    layout->addWidget(m_d->listView.data());

    m_d->listView->setResizeMode(QDeclarativeView::SizeRootObjectToView);

    m_d->listView->rootContext()->setContextProperty(QLatin1String("statesEditorModel"), m_d->statesEditorModel.data());

    // Work around ASSERT in the internal QGraphicsScene that happens when
    // the scene is created + items set dirty in one event loop run (BAUHAUS-459)
    QApplication::processEvents();

    m_d->listView->setSource(QUrl("qrc:/stateseditor/stateslist.qml"));

    if (!m_d->listView->rootObject())
        throw InvalidQmlSourceException(__LINE__, __FUNCTION__, __FILE__);

    m_d->listView->setFocusPolicy(Qt::ClickFocus);
    QApplication::sendEvent(m_d->listView->scene(), new QEvent(QEvent::WindowActivate));

    connect(m_d->listView->rootObject(), SIGNAL(currentStateIndexChanged()), m_d, SLOT(currentStateChanged()));
    connect(m_d->listView->rootObject(), SIGNAL(createNewState()), m_d, SLOT(addState()));
    connect(m_d->listView->rootObject(), SIGNAL(duplicateCurrentState()), m_d, SLOT(duplicateCurrentState()));
    connect(m_d->listView->rootObject(), SIGNAL(deleteState(int)), m_d, SLOT(removeState(int)));

    setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred));

    setWindowTitle(tr("States", "Title of Editor widget"));
}

StatesEditorWidget::~StatesEditorWidget()
{
    delete m_d;
}

void StatesEditorWidget::setup(Model *model)
{
    m_d->model = model;
    if (m_d->statesEditorView.isNull())
        m_d->statesEditorView = new Internal::StatesEditorView(m_d->statesEditorModel.data(), this);
    m_d->statesEditorModel->setStatesEditorView(m_d->statesEditorView.data());

    m_d->model->attachView(m_d->statesEditorView.data());

    // select first state (which is the base state)
    m_d->currentStateChanged();
}

QSize StatesEditorWidget::sizeHint() const
{
    return QSize(9999, 159);
}

}

#include "stateseditorwidget.moc"
<|endoftext|>