<commit_before>#include "JsPlayer.h"

#include <string.h>

#include <node_buffer.h>

#include <nah/NodeHelpers.h>

///////////////////////////////////////////////////////////////////////////////
struct JsPlayer::AsyncData
{
    virtual void process( JsPlayer* ) = 0;
};

///////////////////////////////////////////////////////////////////////////////
struct JsPlayer::AppSinkEventData : public JsPlayer::AsyncData
{
    AppSinkEventData( GstAppSink* appSink, JsPlayer::AppSinkEvent event ) :
        appSink( appSink), event( event ) {}

    void process( JsPlayer* );

    GstAppSink* appSink;
    const JsPlayer::AppSinkEvent event;
};

void JsPlayer::AppSinkEventData::process( JsPlayer* player )
{
    switch( event ) {
     case JsPlayer::AppSinkEvent::NewPreroll:
        player->onNewPreroll( appSink );
        break;
     case JsPlayer::AppSinkEvent::NewSample:
        player->onNewSample( appSink );
        break;
     case JsPlayer::AppSinkEvent::Eos:
        player->onEos( appSink );
        break;
    }
}

///////////////////////////////////////////////////////////////////////////////
v8::Persistent<v8::Function> JsPlayer::_jsConstructor;
std::set<JsPlayer*> JsPlayer::_instances;

void JsPlayer::initJsApi( const v8::Handle<v8::Object>& exports )
{
    node::AtExit( [] ( void* ) { JsPlayer::closeAll(); } );

    gst_init( 0, 0 );

    using namespace v8;

    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope( isolate );

    Local<FunctionTemplate> constructorTemplate = FunctionTemplate::New( isolate, jsCreate );
    constructorTemplate->SetClassName( String::NewFromUtf8( isolate, "Player", v8::String::kInternalizedString ) );

    Local<ObjectTemplate> instanceTemplate = constructorTemplate->InstanceTemplate();
    instanceTemplate->SetInternalFieldCount( 1 );

    SET_METHOD( instanceTemplate, "parseLaunch", &JsPlayer::parseLaunch );
    SET_METHOD( instanceTemplate, "addAppSinkCallback", &JsPlayer::addAppSinkCallback );
    SET_METHOD( instanceTemplate, "setState", &JsPlayer::setState );

    Local<Function> constructor = constructorTemplate->GetFunction();
    _jsConstructor.Reset( isolate, constructor );

    exports->Set( String::NewFromUtf8( isolate, "createPlayer", v8::String::kInternalizedString ), constructor );
    exports->Set( String::NewFromUtf8( isolate, "Player", v8::String::kInternalizedString ), constructor );
}

void JsPlayer::jsCreate( const v8::FunctionCallbackInfo<v8::Value>& args )
{
    using namespace v8;

    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope( isolate );

    Local<Object> thisObject = args.Holder();
    if( args.IsConstructCall() ) {
        JsPlayer* jsPlayer = new JsPlayer( thisObject );
        args.GetReturnValue().Set( jsPlayer->handle() );
    } else {
        Local<Value> argv[] = { args[0] };
        Local<Function> constructor =
            Local<Function>::New( isolate, _jsConstructor );
        args.GetReturnValue().Set( constructor->NewInstance( sizeof( argv ) / sizeof( argv[0] ), argv ) );
    }
}

void JsPlayer::closeAll()
{
    for( JsPlayer* p : _instances ) {
        p->close();
    }

    gst_deinit();
}

JsPlayer::JsPlayer( v8::Local<v8::Object>& thisObject ) :
    _pipeline( nullptr ), _firstSample( true )
{
    Wrap( thisObject );

    _instances.insert( this );

    uv_loop_t* loop = uv_default_loop();

    uv_async_init( loop, &_async,
        [] ( uv_async_t* handle ) {
            if( handle->data )
                reinterpret_cast<JsPlayer*>( handle->data )->handleAsync();
        }
    );
    _async.data = this;

}

JsPlayer::~JsPlayer()
{
    close();

    _instances.erase( this );
}

void JsPlayer::close()
{
    _async.data = nullptr;
    uv_close( reinterpret_cast<uv_handle_t*>( &_async ), 0 );
}

void JsPlayer::handleAsync()
{
    while( !_asyncData.empty() ) {
        std::deque<std::unique_ptr<AsyncData> > tmpData;
        _asyncDataGuard.lock();
        _asyncData.swap( tmpData );
        _asyncDataGuard.unlock();

        for( const auto& i: tmpData ) {
            i->process( this );
        }
    }
}

GstFlowReturn JsPlayer::onNewPrerollProxy( GstAppSink *appSink, gpointer userData )
{
    JsPlayer* player = static_cast<JsPlayer*>( userData );

    player->_asyncDataGuard.lock();
    player->_asyncData.emplace_back( new AppSinkEventData( appSink, NewPreroll ) );
    player->_asyncDataGuard.unlock();
    uv_async_send( &player->_async );

    return GST_FLOW_OK;
}

GstFlowReturn JsPlayer::onNewSampleProxy( GstAppSink *appSink, gpointer userData )
{
    JsPlayer* player = static_cast<JsPlayer*>( userData );

    player->_appSinks[appSink].waitingSample.clear();
    player->_asyncDataGuard.lock();
    player->_asyncData.emplace_back( new AppSinkEventData( appSink, NewSample ) );
    player->_asyncDataGuard.unlock();
    uv_async_send( &player->_async );

    return GST_FLOW_OK;
}

void JsPlayer::onEosProxy( GstAppSink* appSink, gpointer userData )
{
    JsPlayer* player = static_cast<JsPlayer*>( userData );

    player->_asyncDataGuard.lock();
    player->_asyncData.emplace_back( new AppSinkEventData( appSink, Eos ) );
    player->_asyncDataGuard.unlock();
    uv_async_send( &player->_async );
}

void JsPlayer::callCallback( GstAppSink* appSink, JsPlayer::AppSinkEvent event,
                             std::initializer_list<v8::Local<v8::Value> > list )
{
    auto it = _appSinks.find( appSink );
    if( _appSinks.end() == it )
        return;

    if( it->second.callback.IsEmpty() )
        return;

    using namespace v8;

    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope( isolate );

    Local<Function> callbackFunc =
        Local<Function>::New( isolate, _appSinks[appSink].callback );

    std::vector<v8::Local<v8::Value> > argList;

    argList.push_back( Integer::New( isolate, event ) );
    argList.insert( argList.end(), list );
    callbackFunc->Call( handle(), static_cast<int>( argList.size() ), argList.data() );
}

void JsPlayer::onSetup( GstAppSink* appSink, const GstVideoInfo& videoInfo )
{
    if( !appSink )
        return;

    using namespace v8;

    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope( isolate );

    _firstSample = false;

    callCallback( appSink, Setup,
                  { String::NewFromUtf8( isolate, videoInfo.finfo->name, v8::String::kNormalString ),
                    Integer::New( isolate, videoInfo.width ),
                    Integer::New( isolate, videoInfo.height ),
                    Integer::New( isolate, videoInfo.finfo->format ) } );
}

void JsPlayer::onNewPreroll( GstAppSink* appSink )
{
    GstSample* sample = gst_app_sink_pull_preroll( appSink );

    onSample( appSink, sample, true );

    gst_sample_unref( sample );
}

void JsPlayer::onNewSample( GstAppSink* appSink )
{
    if( _appSinks[appSink].waitingSample.test_and_set() )
        return;

    GstSample* sample = gst_app_sink_pull_sample( appSink );

    _appSinks[appSink].waitingSample.test_and_set();

    onSample( appSink, sample, false );

    gst_sample_unref( sample );
}

void JsPlayer::onSample( GstAppSink* appSink, GstSample* sample, bool preroll )
{
    if( !sample )
        return;

    GstVideoInfo videoInfo;

    GstCaps* caps = gst_sample_get_caps( sample );
    if( !caps || !gst_video_info_from_caps( &videoInfo, caps ) )
        return;

    if( _firstSample )
        onSetup( appSink, videoInfo );

    GstBuffer* buffer = gst_sample_get_buffer( sample );

    if( !buffer )
        return;

    GstMapInfo mapInfo;
    if( gst_buffer_map( buffer, &mapInfo, GST_MAP_READ ) ) {
        using namespace v8;

        Isolate* isolate = Isolate::GetCurrent();
        HandleScope scope( isolate );

        v8::MaybeLocal<v8::Object> maybeFrame =
            node::Buffer::New( isolate, reinterpret_cast<char*>( mapInfo.data ), mapInfo.size,
                               [] ( char* data, void* hint ) {}, nullptr );

        Local<v8::Object> frame;
        if( maybeFrame.ToLocal( &frame ) ) {
            frame->ForceSet( String::NewFromUtf8( isolate, "pixelFormatName", v8::String::kInternalizedString ),
                             String::NewFromUtf8( isolate, videoInfo.finfo->name, v8::String::kNormalString ),
                             static_cast<v8::PropertyAttribute>( ReadOnly | DontDelete ) );
            frame->ForceSet( String::NewFromUtf8( isolate, "pixelFormat", v8::String::kInternalizedString ),
                             Integer::New( isolate, videoInfo.finfo->format ),
                             static_cast<v8::PropertyAttribute>( ReadOnly | DontDelete ) );

            frame->ForceSet( String::NewFromUtf8( isolate, "width", v8::String::kInternalizedString ),
                             Integer::New( isolate, videoInfo.width ),
                             static_cast<v8::PropertyAttribute>( ReadOnly | DontDelete ) );
            frame->ForceSet( String::NewFromUtf8( isolate, "height", v8::String::kInternalizedString ),
                             Integer::New( isolate, videoInfo.height ),
                             static_cast<v8::PropertyAttribute>( ReadOnly | DontDelete ) );

            Local<Array> planes = Array::New( isolate, videoInfo.finfo->n_planes );
            for( guint p = 0; p < videoInfo.finfo->n_planes; ++p ) {
                planes->Set( p, Integer::New( isolate, videoInfo.offset[p] ) );
            }

            frame->ForceSet( String::NewFromUtf8( isolate, "planes", v8::String::kInternalizedString ),
                             planes,
                             static_cast<v8::PropertyAttribute>( ReadOnly | DontDelete ) );

            callCallback( appSink, ( preroll ? NewPreroll : NewSample ), { frame } );
        }

        gst_buffer_unmap( buffer, &mapInfo );
    }
}

void JsPlayer::onEos( GstAppSink* appSink )
{
    callCallback( appSink, Eos );
}

bool JsPlayer::parseLaunch( const std::string& pipelineDescription )
{
    if( _pipeline ) {
        _appSinks.clear();
        gst_object_unref( _pipeline );
        _pipeline = nullptr;
        _firstSample = true;
    }

    GError* error = nullptr;
    _pipeline = gst_parse_launch( pipelineDescription.c_str(), &error );

    return ( nullptr != _pipeline );
}

bool JsPlayer::addAppSinkCallback( const std::string& appSinkName, v8::Local<v8::Value> value )
{
    if( !_pipeline || appSinkName.empty() )
        return false;

    GstElement* sink = gst_bin_get_by_name( GST_BIN( _pipeline ), appSinkName.c_str() );
    if( !sink )
        return false;

    GstAppSink* appSink = GST_APP_SINK_CAST( sink );
    if( !appSink )
        return appSink;

    using namespace v8;

    Local<Function> callbackFunc = Local<Function>::Cast( value );
    if( callbackFunc.IsEmpty() )
        return false;

    auto it = _appSinks.find( appSink );
    if( _appSinks.end() == it ) {
        gst_app_sink_set_drop( appSink, true );
        gst_app_sink_set_max_buffers( appSink, 1 );
        GstAppSinkCallbacks callbacks = { onEosProxy, onNewPrerollProxy, onNewSampleProxy };
        gst_app_sink_set_callbacks( appSink, &callbacks, this, nullptr );
        it = _appSinks.emplace( appSink, AppSinkData() ).first;
    }

    AppSinkData& sinkData = it->second;
    sinkData.callback.Reset( Isolate::GetCurrent(), callbackFunc );
    sinkData.waitingSample.test_and_set();
}

void JsPlayer::setState( unsigned state )
{
    if( _pipeline )
        gst_element_set_state( _pipeline, static_cast<GstState>( state ) );
}
<commit_msg>state constants added<commit_after>#include "JsPlayer.h"

#include <string.h>

#include <node_buffer.h>

#include <nah/NodeHelpers.h>

///////////////////////////////////////////////////////////////////////////////
struct JsPlayer::AsyncData
{
    virtual void process( JsPlayer* ) = 0;
};

///////////////////////////////////////////////////////////////////////////////
struct JsPlayer::AppSinkEventData : public JsPlayer::AsyncData
{
    AppSinkEventData( GstAppSink* appSink, JsPlayer::AppSinkEvent event ) :
        appSink( appSink), event( event ) {}

    void process( JsPlayer* );

    GstAppSink* appSink;
    const JsPlayer::AppSinkEvent event;
};

void JsPlayer::AppSinkEventData::process( JsPlayer* player )
{
    switch( event ) {
     case JsPlayer::AppSinkEvent::NewPreroll:
        player->onNewPreroll( appSink );
        break;
     case JsPlayer::AppSinkEvent::NewSample:
        player->onNewSample( appSink );
        break;
     case JsPlayer::AppSinkEvent::Eos:
        player->onEos( appSink );
        break;
    }
}

///////////////////////////////////////////////////////////////////////////////
v8::Persistent<v8::Function> JsPlayer::_jsConstructor;
std::set<JsPlayer*> JsPlayer::_instances;

void JsPlayer::initJsApi( const v8::Handle<v8::Object>& exports )
{
    node::AtExit( [] ( void* ) { JsPlayer::closeAll(); } );

    gst_init( 0, 0 );

    using namespace v8;

    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope( isolate );

    Local<FunctionTemplate> constructorTemplate = FunctionTemplate::New( isolate, jsCreate );
    constructorTemplate->SetClassName( String::NewFromUtf8( isolate, "Player", v8::String::kInternalizedString ) );

    Local<ObjectTemplate> instanceTemplate = constructorTemplate->InstanceTemplate();
    instanceTemplate->SetInternalFieldCount( 1 );

    instanceTemplate->Set( String::NewFromUtf8( isolate, "GST_STATE_VOID_PENDING", v8::String::kInternalizedString ),
                           Integer::New( isolate, GST_STATE_VOID_PENDING ),
                           static_cast<v8::PropertyAttribute>( ReadOnly | DontDelete ) );
    instanceTemplate->Set( String::NewFromUtf8( isolate, "GST_STATE_NULL", v8::String::kInternalizedString ),
                           Integer::New( isolate, GST_STATE_NULL ),
                           static_cast<v8::PropertyAttribute>( ReadOnly | DontDelete ) );
    instanceTemplate->Set( String::NewFromUtf8( isolate, "GST_STATE_READY", v8::String::kInternalizedString ),
                           Integer::New( isolate, GST_STATE_READY ),
                           static_cast<v8::PropertyAttribute>( ReadOnly | DontDelete ) );
    instanceTemplate->Set( String::NewFromUtf8( isolate, "GST_STATE_PAUSED", v8::String::kInternalizedString ),
                           Integer::New( isolate, GST_STATE_PAUSED ),
                           static_cast<v8::PropertyAttribute>( ReadOnly | DontDelete ) );
    instanceTemplate->Set( String::NewFromUtf8( isolate, "GST_STATE_PLAYING", v8::String::kInternalizedString ),
                           Integer::New( isolate, GST_STATE_PLAYING ),
                           static_cast<v8::PropertyAttribute>( ReadOnly | DontDelete ) );

    SET_METHOD( instanceTemplate, "parseLaunch", &JsPlayer::parseLaunch );
    SET_METHOD( instanceTemplate, "addAppSinkCallback", &JsPlayer::addAppSinkCallback );
    SET_METHOD( instanceTemplate, "setState", &JsPlayer::setState );

    Local<Function> constructor = constructorTemplate->GetFunction();
    _jsConstructor.Reset( isolate, constructor );

    exports->Set( String::NewFromUtf8( isolate, "createPlayer", v8::String::kInternalizedString ), constructor );
    exports->Set( String::NewFromUtf8( isolate, "Player", v8::String::kInternalizedString ), constructor );
}

void JsPlayer::jsCreate( const v8::FunctionCallbackInfo<v8::Value>& args )
{
    using namespace v8;

    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope( isolate );

    Local<Object> thisObject = args.Holder();
    if( args.IsConstructCall() ) {
        JsPlayer* jsPlayer = new JsPlayer( thisObject );
        args.GetReturnValue().Set( jsPlayer->handle() );
    } else {
        Local<Value> argv[] = { args[0] };
        Local<Function> constructor =
            Local<Function>::New( isolate, _jsConstructor );
        args.GetReturnValue().Set( constructor->NewInstance( sizeof( argv ) / sizeof( argv[0] ), argv ) );
    }
}

void JsPlayer::closeAll()
{
    for( JsPlayer* p : _instances ) {
        p->close();
    }

    gst_deinit();
}

JsPlayer::JsPlayer( v8::Local<v8::Object>& thisObject ) :
    _pipeline( nullptr ), _firstSample( true )
{
    Wrap( thisObject );

    _instances.insert( this );

    uv_loop_t* loop = uv_default_loop();

    uv_async_init( loop, &_async,
        [] ( uv_async_t* handle ) {
            if( handle->data )
                reinterpret_cast<JsPlayer*>( handle->data )->handleAsync();
        }
    );
    _async.data = this;

}

JsPlayer::~JsPlayer()
{
    close();

    _instances.erase( this );
}

void JsPlayer::close()
{
    _async.data = nullptr;
    uv_close( reinterpret_cast<uv_handle_t*>( &_async ), 0 );
}

void JsPlayer::handleAsync()
{
    while( !_asyncData.empty() ) {
        std::deque<std::unique_ptr<AsyncData> > tmpData;
        _asyncDataGuard.lock();
        _asyncData.swap( tmpData );
        _asyncDataGuard.unlock();

        for( const auto& i: tmpData ) {
            i->process( this );
        }
    }
}

GstFlowReturn JsPlayer::onNewPrerollProxy( GstAppSink *appSink, gpointer userData )
{
    JsPlayer* player = static_cast<JsPlayer*>( userData );

    player->_asyncDataGuard.lock();
    player->_asyncData.emplace_back( new AppSinkEventData( appSink, NewPreroll ) );
    player->_asyncDataGuard.unlock();
    uv_async_send( &player->_async );

    return GST_FLOW_OK;
}

GstFlowReturn JsPlayer::onNewSampleProxy( GstAppSink *appSink, gpointer userData )
{
    JsPlayer* player = static_cast<JsPlayer*>( userData );

    player->_appSinks[appSink].waitingSample.clear();
    player->_asyncDataGuard.lock();
    player->_asyncData.emplace_back( new AppSinkEventData( appSink, NewSample ) );
    player->_asyncDataGuard.unlock();
    uv_async_send( &player->_async );

    return GST_FLOW_OK;
}

void JsPlayer::onEosProxy( GstAppSink* appSink, gpointer userData )
{
    JsPlayer* player = static_cast<JsPlayer*>( userData );

    player->_asyncDataGuard.lock();
    player->_asyncData.emplace_back( new AppSinkEventData( appSink, Eos ) );
    player->_asyncDataGuard.unlock();
    uv_async_send( &player->_async );
}

void JsPlayer::callCallback( GstAppSink* appSink, JsPlayer::AppSinkEvent event,
                             std::initializer_list<v8::Local<v8::Value> > list )
{
    auto it = _appSinks.find( appSink );
    if( _appSinks.end() == it )
        return;

    if( it->second.callback.IsEmpty() )
        return;

    using namespace v8;

    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope( isolate );

    Local<Function> callbackFunc =
        Local<Function>::New( isolate, _appSinks[appSink].callback );

    std::vector<v8::Local<v8::Value> > argList;

    argList.push_back( Integer::New( isolate, event ) );
    argList.insert( argList.end(), list );
    callbackFunc->Call( handle(), static_cast<int>( argList.size() ), argList.data() );
}

void JsPlayer::onSetup( GstAppSink* appSink, const GstVideoInfo& videoInfo )
{
    if( !appSink )
        return;

    using namespace v8;

    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope( isolate );

    _firstSample = false;

    callCallback( appSink, Setup,
                  { String::NewFromUtf8( isolate, videoInfo.finfo->name, v8::String::kNormalString ),
                    Integer::New( isolate, videoInfo.width ),
                    Integer::New( isolate, videoInfo.height ),
                    Integer::New( isolate, videoInfo.finfo->format ) } );
}

void JsPlayer::onNewPreroll( GstAppSink* appSink )
{
    GstSample* sample = gst_app_sink_pull_preroll( appSink );

    onSample( appSink, sample, true );

    gst_sample_unref( sample );
}

void JsPlayer::onNewSample( GstAppSink* appSink )
{
    if( _appSinks[appSink].waitingSample.test_and_set() )
        return;

    GstSample* sample = gst_app_sink_pull_sample( appSink );

    _appSinks[appSink].waitingSample.test_and_set();

    onSample( appSink, sample, false );

    gst_sample_unref( sample );
}

void JsPlayer::onSample( GstAppSink* appSink, GstSample* sample, bool preroll )
{
    if( !sample )
        return;

    GstVideoInfo videoInfo;

    GstCaps* caps = gst_sample_get_caps( sample );
    if( !caps || !gst_video_info_from_caps( &videoInfo, caps ) )
        return;

    if( _firstSample )
        onSetup( appSink, videoInfo );

    GstBuffer* buffer = gst_sample_get_buffer( sample );

    if( !buffer )
        return;

    GstMapInfo mapInfo;
    if( gst_buffer_map( buffer, &mapInfo, GST_MAP_READ ) ) {
        using namespace v8;

        Isolate* isolate = Isolate::GetCurrent();
        HandleScope scope( isolate );

        v8::MaybeLocal<v8::Object> maybeFrame =
            node::Buffer::New( isolate, reinterpret_cast<char*>( mapInfo.data ), mapInfo.size,
                               [] ( char* data, void* hint ) {}, nullptr );

        Local<v8::Object> frame;
        if( maybeFrame.ToLocal( &frame ) ) {
            frame->ForceSet( String::NewFromUtf8( isolate, "pixelFormatName", v8::String::kInternalizedString ),
                             String::NewFromUtf8( isolate, videoInfo.finfo->name, v8::String::kNormalString ),
                             static_cast<v8::PropertyAttribute>( ReadOnly | DontDelete ) );
            frame->ForceSet( String::NewFromUtf8( isolate, "pixelFormat", v8::String::kInternalizedString ),
                             Integer::New( isolate, videoInfo.finfo->format ),
                             static_cast<v8::PropertyAttribute>( ReadOnly | DontDelete ) );

            frame->ForceSet( String::NewFromUtf8( isolate, "width", v8::String::kInternalizedString ),
                             Integer::New( isolate, videoInfo.width ),
                             static_cast<v8::PropertyAttribute>( ReadOnly | DontDelete ) );
            frame->ForceSet( String::NewFromUtf8( isolate, "height", v8::String::kInternalizedString ),
                             Integer::New( isolate, videoInfo.height ),
                             static_cast<v8::PropertyAttribute>( ReadOnly | DontDelete ) );

            Local<Array> planes = Array::New( isolate, videoInfo.finfo->n_planes );
            for( guint p = 0; p < videoInfo.finfo->n_planes; ++p ) {
                planes->Set( p, Integer::New( isolate, videoInfo.offset[p] ) );
            }

            frame->ForceSet( String::NewFromUtf8( isolate, "planes", v8::String::kInternalizedString ),
                             planes,
                             static_cast<v8::PropertyAttribute>( ReadOnly | DontDelete ) );

            callCallback( appSink, ( preroll ? NewPreroll : NewSample ), { frame } );
        }

        gst_buffer_unmap( buffer, &mapInfo );
    }
}

void JsPlayer::onEos( GstAppSink* appSink )
{
    callCallback( appSink, Eos );
}

bool JsPlayer::parseLaunch( const std::string& pipelineDescription )
{
    if( _pipeline ) {
        _appSinks.clear();
        gst_object_unref( _pipeline );
        _pipeline = nullptr;
        _firstSample = true;
    }

    GError* error = nullptr;
    _pipeline = gst_parse_launch( pipelineDescription.c_str(), &error );

    return ( nullptr != _pipeline );
}

bool JsPlayer::addAppSinkCallback( const std::string& appSinkName, v8::Local<v8::Value> value )
{
    if( !_pipeline || appSinkName.empty() )
        return false;

    GstElement* sink = gst_bin_get_by_name( GST_BIN( _pipeline ), appSinkName.c_str() );
    if( !sink )
        return false;

    GstAppSink* appSink = GST_APP_SINK_CAST( sink );
    if( !appSink )
        return appSink;

    using namespace v8;

    Local<Function> callbackFunc = Local<Function>::Cast( value );
    if( callbackFunc.IsEmpty() )
        return false;

    auto it = _appSinks.find( appSink );
    if( _appSinks.end() == it ) {
        gst_app_sink_set_drop( appSink, true );
        gst_app_sink_set_max_buffers( appSink, 1 );
        GstAppSinkCallbacks callbacks = { onEosProxy, onNewPrerollProxy, onNewSampleProxy };
        gst_app_sink_set_callbacks( appSink, &callbacks, this, nullptr );
        it = _appSinks.emplace( appSink, AppSinkData() ).first;
    }

    AppSinkData& sinkData = it->second;
    sinkData.callback.Reset( Isolate::GetCurrent(), callbackFunc );
    sinkData.waitingSample.test_and_set();
}

void JsPlayer::setState( unsigned state )
{
    if( _pipeline )
        gst_element_set_state( _pipeline, static_cast<GstState>( state ) );
}
<|endoftext|>


<commit_before>/* Generated from orogen/lib/orogen/templates/typekit/typelib/OpaqueType.cpp */

#include "OpaqueConvertions.hpp"
#include "Types.hpp"
#include <rtt/typelib/OpaqueTypelibMarshaller.hpp>
#include "transports/typelib/Registration.hpp"

orogen_transports::TypelibMarshallerBase* orogen_typekits::<%= type.method_name %>_TypelibMarshaller(Typelib::Registry const& registry)
{
    return new orogen_transports::OpaqueTypelibMarshaller< <%= intermediate.cxx_name %>, <%= type.cxx_name %>, <%= needs_copy %> >("<%= intermediate.cxx_name %>", "<%= type.name %>", registry);
}

<commit_msg>fix intermediate type name in typelib's marshaller for opaque types<commit_after>/* Generated from orogen/lib/orogen/templates/typekit/typelib/OpaqueType.cpp */

#include "OpaqueConvertions.hpp"
#include "Types.hpp"
#include <rtt/typelib/OpaqueTypelibMarshaller.hpp>
#include "transports/typelib/Registration.hpp"

orogen_transports::TypelibMarshallerBase* orogen_typekits::<%= type.method_name %>_TypelibMarshaller(Typelib::Registry const& registry)
{
    return new orogen_transports::OpaqueTypelibMarshaller< <%= intermediate.cxx_name %>, <%= type.cxx_name %>, <%= needs_copy %> >("<%= intermediate.name %>", "<%= type.name %>", registry);
}

<|endoftext|>


<commit_before>#include "kernel.h"
#include "raster.h"
#include "rastercoverage.h"
#include "pixeliterator.h"
#include "connectorinterface.h"
#include "symboltable.h"
#include "domainitem.h"
#include "itemdomain.h"
#include "numericitem.h"
#include "numericitemrange.h"
#include "ilwisoperation.h"

quint64 Ilwis::GridBlockInternal::_blockid = 0;

using namespace Ilwis;

RasterCoverage::RasterCoverage()
{
}

RasterCoverage::RasterCoverage(const Resource& res) : Coverage(res){

}

RasterCoverage::~RasterCoverage()
{
}

const IGeoReference& RasterCoverage::georeference() const
{
    return _georef;
}

void RasterCoverage::georeference(const IGeoReference &grf)
{
    _georef = grf;
    if ( _grid.isNull() == false) { // remove the current grid, all has become uncertain
        _grid.reset(0);

    }
    if ( _georef.isValid()) {
        _georef->compute();
        setCoordinateSystem(grf->coordinateSystem()); // mandatory
    }
}

IlwisTypes RasterCoverage::ilwisType() const
{
    return itRASTER;
}

RasterCoverage *RasterCoverage::copy()
{
    RasterCoverage *gc = new RasterCoverage();
    copyTo(gc);
    return gc;

}

void RasterCoverage::copyBinary(const IRasterCoverage& gc, int index) {
    IRasterCoverage gcNew;
    gcNew.set(this);
    Size inputSize =  gc->size();
    Size sz(inputSize.xsize(),inputSize.ysize(), 1);
    gcNew->georeference()->size(sz);
    PixelIterator iterIn(gc, Box3D<>(Voxel(0,0,index), Voxel(inputSize.xsize(), inputSize.ysize(), index + 1)));
    PixelIterator iterOut(gcNew, Box3D<>(Size(inputSize.xsize(), inputSize.ysize(), 1)));
    for_each(iterOut, iterOut.end(), [&](double& v){
         v = *iterIn;
        ++iterIn;
    });
}

//IRasterCoverage RasterCoverage::get(quint32 index1, quint32 index2)
//{
//    IRasterCoverage gcovParent;
//    gcovParent.set(this);
//    IRasterCoverage gcov = OperationHelperRaster::initialize(gcovParent,itRASTER, itDOMAIN | itCOORDSYSTEM | itGEOREF);
//    gcov->size(Size(size().xsize(), size().ysize()));
//    gcov->_grid.reset(gcov->_grid->clone(index1, index2));

//    return gcov;

//}

Grid *RasterCoverage::grid()
{
    Locker lock(_mutex);
    if ( _georef->isValid() && !connector().isNull()) {
        if ( _grid.isNull()) {
            _grid.reset(connector()->loadGridData(this));
            if (_grid.isNull())
                return 0;
        }
        Grid *grd = _grid.data();
        return grd;
    }
    return 0;
}

void RasterCoverage::copyTo(IlwisObject *obj)
{
    Locker lock(_mutex);
    Coverage::copyTo(obj);
    RasterCoverage *gc = static_cast<RasterCoverage *>(obj);
    gc->_georef = _georef;
    if ( _grid) {
        gc->_grid.reset(_grid->clone());
    }

}

Resource RasterCoverage::resource(int mode) const
{
    Resource res = Coverage::resource(mode);
    if ( mode & IlwisObject::cmEXTENDED) {
        res["georeference()"] = georeference()->id();
        res.setExtendedType( res.extendedType() | itGEOREF);
    }
    return res;
}

Size RasterCoverage::size() const
{
    if (_size.isValid() && !_size.isNull())
        return _size;
    if (!_grid.isNull())
        const_cast<RasterCoverage *>(this)->_size = _grid->size();
    else if ( _georef.isValid())
        const_cast<RasterCoverage *>(this)->_size = _georef->size();

    return _size;

}

void RasterCoverage::unloadBinary() {
    if (!_grid == NULL) {
        return _grid->unload();
    }
}

void RasterCoverage::size(const Size &sz)
{
    // size must always be positive or undefined
    if (sz.xsize() > 0 && sz.ysize() > 0) {
        _size = sz;
        if (!_grid.isNull())
            _grid->setSize(sz);
        if (_georef.isValid())
            _georef->size(sz);
    }

}

<commit_msg>readability<commit_after>#include "kernel.h"
#include "raster.h"
#include "rastercoverage.h"
#include "pixeliterator.h"
#include "connectorinterface.h"
#include "symboltable.h"
#include "domainitem.h"
#include "itemdomain.h"
#include "numericitem.h"
#include "numericitemrange.h"
#include "ilwisoperation.h"

quint64 Ilwis::GridBlockInternal::_blockid = 0;

using namespace Ilwis;

RasterCoverage::RasterCoverage()
{
}

RasterCoverage::RasterCoverage(const Resource& res) : Coverage(res){

}

RasterCoverage::~RasterCoverage()
{
}

const IGeoReference& RasterCoverage::georeference() const
{
    return _georef;
}

void RasterCoverage::georeference(const IGeoReference &grf)
{
    _georef = grf;
    if ( _grid.isNull() == false) { // remove the current grid, all has become uncertain
        _grid.reset(0);

    }
    if ( _georef.isValid()) {
        _georef->compute();
        setCoordinateSystem(grf->coordinateSystem()); // mandatory
    }
}

IlwisTypes RasterCoverage::ilwisType() const
{
    return itRASTER;
}

RasterCoverage *RasterCoverage::copy()
{
    RasterCoverage *gc = new RasterCoverage();
    copyTo(gc);
    return gc;

}

void RasterCoverage::copyBinary(const IRasterCoverage& gc, int index) {
    IRasterCoverage gcNew;
    gcNew.set(this);
    Size inputSize =  gc->size();
    Size sz(inputSize.xsize(),inputSize.ysize(), 1);
    gcNew->georeference()->size(sz);
    PixelIterator iterIn(gc, Box3D<>(Voxel(0,0,index), Voxel(inputSize.xsize(), inputSize.ysize(), index + 1)));
    PixelIterator iterOut(gcNew, Box3D<>(Size(inputSize.xsize(), inputSize.ysize(), 1)));
    for_each(iterOut, iterOut.end(), [&](double& v){
         v = *iterIn;
        ++iterIn;
    });
}

//IRasterCoverage RasterCoverage::get(quint32 index1, quint32 index2)
//{
//    IRasterCoverage gcovParent;
//    gcovParent.set(this);
//    IRasterCoverage gcov = OperationHelperRaster::initialize(gcovParent,itRASTER, itDOMAIN | itCOORDSYSTEM | itGEOREF);
//    gcov->size(Size(size().xsize(), size().ysize()));
//    gcov->_grid.reset(gcov->_grid->clone(index1, index2));

//    return gcov;

//}

Grid *RasterCoverage::grid()
{
    Locker lock(_mutex);
    if ( _georef->isValid() && !connector().isNull()) {
        if ( _grid.isNull()) {
            _grid.reset(connector()->loadGridData(this));
            if (_grid.isNull())
                return 0;
        }
        Grid *grd = _grid.data();
        return grd;
    }
    return 0;
}

void RasterCoverage::copyTo(IlwisObject *obj)
{
    Locker lock(_mutex);
    Coverage::copyTo(obj);
    RasterCoverage *gc = static_cast<RasterCoverage *>(obj);
    gc->_georef = _georef;
    if ( _grid) {
        gc->_grid.reset(_grid->clone());
    }

}

Resource RasterCoverage::resource(int mode) const
{
    Resource res = Coverage::resource(mode);
    if ( mode & IlwisObject::cmEXTENDED) {
        res["georeference()"] = georeference()->id();
        res.setExtendedType( res.extendedType() | itGEOREF);
    }
    return res;
}

Size RasterCoverage::size() const
{
    if (_size.isValid() && !_size.isNull())
        return _size;
    if (!_grid.isNull())
        const_cast<RasterCoverage *>(this)->_size = _grid->size();
    else if ( _georef.isValid())
        const_cast<RasterCoverage *>(this)->_size = _georef->size();

    return _size;

}

void RasterCoverage::unloadBinary() {
    if (_grid != 0) {
        return _grid->unload();
    }
}

void RasterCoverage::size(const Size &sz)
{
    // size must always be positive or undefined
    if (sz.xsize() > 0 && sz.ysize() > 0) {
        _size = sz;
        if (!_grid.isNull())
            _grid->setSize(sz);
        if (_georef.isValid())
            _georef->size(sz);
    }
}

<|endoftext|>


<commit_before>//
// SRTerrain class : a subclass of vtDynTerrainGeom which encapsulates
//  Stefan Roettger's CLOD algorithm.
//
// utilizes: Roettger's MINI library implementation
// http://wwwvis.informatik.uni-stuttgart.de/~roettger
//
// Copyright (c) 2002-2005 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "vtlib/vtlib.h"
#include "SRTerrain.h"
#include "vtdata/vtLog.h"

#if VTLIB_NI
// stub
SRTerrain::SRTerrain() {}
SRTerrain::~SRTerrain() {}
float SRTerrain::GetElevation(int iX, int iZ, bool bTrue) const { return 0; }
void SRTerrain::GetWorldLocation(int i, int j, FPoint3 &p, bool bTrue) const {}
void SRTerrain::DoCulling(const vtCamera *pCam) {}
void SRTerrain::DoRender() {}
void SRTerrain::SetVerticalExag(float fExag) {}
DTErr SRTerrain::Init(const vtElevationGrid *pGrid, float fZScale) { return DTErr_NOMEM; }
#else

#include "mini.h"
#include "ministub.hpp"

using namespace mini;
#ifdef _MSC_VER
#pragma comment( lib, "libMini.lib" )
#endif

/////////////////////////////////////////////////////////////////////////////

//
// Constructor/destructor
//
SRTerrain::SRTerrain() : vtDynTerrainGeom()
{
	m_fResolution	= 10000.0f;
	m_fHResolution	= 20000.0f;
	m_fLResolution	=     0.0f;
	m_pMini = NULL;
}

SRTerrain::~SRTerrain()
{
	if (m_pMini)
	{
		delete m_pMini;
		m_pMini = NULL;
	}
}

/////////////////////////////////////////////////////////////////////////////

//
// Unfortunately the following statics are required because libMini only
// supports some functionality by callback, and the callback is only a
// simple C function which has no context to tell us which terrain.
//
static const vtElevationGrid *s_pGrid;
static SRTerrain *s_pSRTerrain;
static int myfancnt, myvtxcnt;
static int s_iRows;

void beginfan_vtp()
{
	if (myfancnt++>0)
		glEnd();
	glBegin(GL_TRIANGLE_FAN);
	myvtxcnt-=2;	// 2 vertices are needed to start each fan
}

void fanvertex_vtp(float x, float y, float z)
{
	glVertex3f(x,y,z);
	myvtxcnt++;
}

void notify_vtp(int i, int j, int size)
{
	// check to see if we need to switch texture
	if (s_pSRTerrain->m_iTPatchDim > 1 && size == s_pSRTerrain->m_iBlockSize)
	{
		int a = i / size;
		int b = j / size;
		s_pSRTerrain->LoadBlockMaterial(a, b);
	}
}

short int getelevation_vtp1(int i, int j, int size, void *data_unused)
{
	return s_pGrid->GetValue(i, s_iRows-1-j);
}

float getelevation_vtp2(int i, int j, int size, void *data_unused)
{
	return s_pGrid->GetFValue(i, s_iRows-1-j);
}

//
// Initialize the terrain data
// fZScale converts from height values (meters) to world coordinates
//
DTErr SRTerrain::Init(const vtElevationGrid *pGrid, float fZScale)
{
	// Initializes necessary field of the parent class
	DTErr err = BasicInit(pGrid);
	if (err != DTErr_OK)
		return err;

	if (m_iColumns != m_iRows)
		return DTErr_NOTSQUARE;

	// compute n (log2 of grid size)
	// ensure that the grid is size (1 << n) + 1
	int n = vt_log2(m_iColumns - 1);
	int required_size = (1<<n) + 1;
	if (m_iColumns != required_size || m_iRows != required_size)
		return DTErr_NOTPOWER2;

	int size = m_iColumns;
	float dim = m_fXStep;
	float cellaspect = m_fZStep / m_fXStep;

	s_pGrid = pGrid;
	s_iRows = m_iRows;

#if 0
	// NOTE: the following workaround is no longer needed with libMini 5.02
	//
	// Totally strange but repeatable behavior: runtime exit in Release-mode
	//  libMini with values over a certain level.  Workaround here!
	// Exit happens if (scale * maximum_height / dim > 967)
	//
	// 	scale * maximum_height / dim > 967
	//	scale > dim * 967 / maximum_height
	//
	float fMin, fMax;
	pGrid->GetHeightExtents(fMin, fMax);
	// Avoid trouble with fMax small or zero
	if (fMax < 10) fMax = 10;
	// compute the largest supported value for MaxScale
	float fMaxMax = dim * 960 / fMax;
	// values greater than 10 are unnecessarily large
	if (fMaxMax > 10)
		fMaxMax = 10;
	m_fMaximumScale = fMaxMax;
#else
	// This maxiumum scale is a reasonable tradeoff between the exaggeration
	//  that the user is likely to need, and numerical precision issues.
	m_fMaximumScale = 10;
#endif

	m_fHeightScale = fZScale;
	m_fDrawScale = m_fHeightScale / m_fMaximumScale;

	if (pGrid->IsFloatMode())
	{
		float *image = NULL;
		m_pMini = new ministub(image,
				&size, &dim, m_fMaximumScale, cellaspect,
				0.0f, 0.0f, 0.0f,	// grid center
				beginfan_vtp, fanvertex_vtp, notify_vtp,
				getelevation_vtp2);
	}
	else
	{
		short *image = NULL;
		m_pMini = new ministub(image,
				&size, &dim, m_fMaximumScale, cellaspect,
				0.0f, 0.0f, 0.0f,	// grid center
				beginfan_vtp, fanvertex_vtp, notify_vtp,
				getelevation_vtp1);
	}

	m_iDrawnTriangles = -1;
	m_iBlockSize = m_iColumns / 4;

	return DTErr_OK;
}

void SRTerrain::SetVerticalExag(float fExag)
{
	m_fHeightScale = fExag;

	// safety check
	if (m_fHeightScale > m_fMaximumScale)
		m_fHeightScale = m_fMaximumScale;

	m_fDrawScale = m_fHeightScale / m_fMaximumScale;
}

//
// This will be called once per frame, during the culling pass.
//
// However, libMini does not allow you to call the culling pass
// independently of the rendering pass, so we cannot do culling here.
// Instead, just store the values for later use.
//
void SRTerrain::DoCulling(const vtCamera *pCam)
{
	// Grab necessary values from the VTP Scene framework, store for later
	m_eyepos_ogl = pCam->GetTrans();
	m_window_size = vtGetScene()->GetWindowSize();
	m_fAspect = (float)m_window_size.x / m_window_size.y;
	m_fNear = pCam->GetHither();
	m_fFar = pCam->GetYon();

	// Get up vector and direction vector from camera matrix
	FMatrix4 mat;
	pCam->GetTransform1(mat);
	FPoint3 up(0.0f, 1.0f, 0.0f);
	mat.TransformVector(up, eye_up);

	FPoint3 forward(0.0f, 0.0f, -1.0f);
	mat.TransformVector(forward, eye_forward);

	if (pCam->IsOrtho())
	{
		// libMini supports orthographic viewing as of libMini 5.0.
		// A negative FOV value indicates to the library that the FOV is
		//  actually the orthographic height of the camera.
		m_fFOVY = pCam->GetWidth() / m_fAspect;
		m_fFOVY = -m_fFOVY;
	}
	else
	{
		float fov = pCam->GetFOV();
		float fov_y2 = atan(tan (fov/2) / m_fAspect);
		m_fFOVY = fov_y2 * 2.0f * 180 / PIf;
	}
}

void SRTerrain::DoRender()
{
	// Prepare the render state for our OpenGL usage
	PreRender();

	// Render the triangles
	RenderSurface();

	// Clean up
	PostRender();
}

void SRTerrain::LoadSingleMaterial()
{
	// single texture for the whole terrain
	vtMaterial *pMat = GetMaterial(0);
	if (pMat)
	{
		pMat->Apply();
		SetupTexGen(1.0f);
	}
}

void SRTerrain::LoadBlockMaterial(int a, int b)
{
	// we can't change the texture between glBegin/glEnd
	if (myfancnt++>0)
		glEnd();

	// each block has it's own texture map
	int matidx = a*m_iTPatchDim + (m_iTPatchDim-1-b);
	vtMaterial *pMat = GetMaterial(matidx);
	if (pMat)
	{
		pMat->Apply();
		SetupBlockTexGen(a, b);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	}

	glBegin(GL_TRIANGLE_FAN);
}

void SRTerrain::RenderSurface()
{
	s_pSRTerrain = this;

	if (m_iTPatchDim == 1)
		LoadSingleMaterial();

	RenderPass();

	// how to do a second rendering pass
	if (m_bDetailTexture)
	{
		// once again, with the detail texture material
		m_pDetailMat->Apply();

		// the uv tiling is different (usually highly repetitive)
		SetupTexGen(m_fDetailTiling);

		// draw the second pass
		glPolygonOffset(-1.0f, -1.0f);
		glEnable(GL_POLYGON_OFFSET_FILL);
		RenderPass();
		glDisable(GL_POLYGON_OFFSET_FILL);
	}
	DisableTexGen();
}

void SRTerrain::RenderPass()
{
	float ex = m_eyepos_ogl.x;
	float ey = m_eyepos_ogl.y;
	float ez = m_eyepos_ogl.z;

	float fov = m_fFOVY;

	float ux = eye_up.x;
	float uy = eye_up.y;
	float uz = eye_up.z;

	float dx = eye_forward.x;
	float dy = eye_forward.y;
	float dz = eye_forward.z;

	myfancnt = myvtxcnt = 0;

	// Convert the eye location to the unusual coordinate scheme of libMini.
	ex -= (m_iColumns/2)*m_fXStep;
	ez += (m_iRows/2)*m_fZStep;

	m_pMini->draw(m_fResolution,
				ex, ey, ez,
				dx, dy, dz,
				ux, uy, uz,
				fov, m_fAspect,
				m_fNear, m_fFar,
				m_fDrawScale);

	if (myfancnt>0) glEnd();

	// We are drawing fans, so the number of triangles is roughly equal to
	// number of vertices
	m_iDrawnTriangles = myvtxcnt;

	// adaptively adjust resolution threshold up or down to attain
	// the desired polygon (vertex) count target
	int diff = m_iDrawnTriangles - m_iPolygonTarget;
	int iRange = m_iPolygonTarget / 10;		// ensure within 10%

	// If we aren't within the triangle count range adjust the input resolution
	// like a binary search
	if (diff < -iRange || diff > iRange)
	{
//		VTLOG("diff %d, ", diff);
		if (diff < -iRange)
		{
			m_fLResolution = m_fResolution;

			// if the high end isn't high enough, double it
			if (m_fLResolution + 5 >= m_fHResolution)
			{
//				VTLOG("increase HRes, ");
				m_fHResolution *= 10;
			}
		}
		else
		{
			m_fHResolution = m_fResolution;
			if (m_fLResolution + 5 >= m_fHResolution)
			{
//				VTLOG("decrease LRes, ");
				m_fLResolution = 0;
			}
		}

		m_fResolution = m_fLResolution + (m_fHResolution - m_fLResolution) / 2;
//		VTLOG("rez: [%.1f, %.1f, %.1f] (%d/%d)\n", m_fLResolution, m_fResolution, m_fHResolution, m_iDrawnTriangles, m_iPolygonTarget);

		// keep the error within reasonable bounds
		if (m_fResolution < 5.0f)
			m_fResolution = 5.0f;
		if (m_fResolution > 4E7)
			m_fResolution = 4E7;
	}
}

//
// These methods are called when the framework needs to know the surface
// position of the terrain at a given grid point.  Supply the height
// value from our own data structures.
//
float SRTerrain::GetElevation(int iX, int iZ, bool bTrue) const
{
	float height = m_pMini->getheight(iX, iZ);

	if (iX<0 || iX>m_iColumns-1 || iZ<0 || iZ>m_iRows-1)
		return 0.0f;

	if (bTrue)
		// convert stored value to true value
		return height / m_fMaximumScale;
	else
		// convert stored value to drawn value
		return height * m_fDrawScale;
}

void SRTerrain::GetWorldLocation(int i, int j, FPoint3 &p, bool bTrue) const
{
	float height = m_pMini->getheight(i, j);

	if (bTrue)
		// convert stored value to true value
		height /= m_fMaximumScale;
	else
		// convert stored value to drawn value
		height *= m_fDrawScale;

	p.Set(m_fXLookup[i],
		  height,
		  m_fZLookup[j]);
}
void SRTerrain::SetPolygonCount(int iPolygonCount)
{
	vtDynTerrainGeom::SetPolygonCount(iPolygonCount);
	m_fResolution = iPolygonCount * 5;
	m_fHResolution = 2 * m_fResolution;
	m_fLResolution = 0;
}

#endif	// VTLIB_NI
<commit_msg>optional linking with libMinid.lib for core development<commit_after>//
// SRTerrain class : a subclass of vtDynTerrainGeom which encapsulates
//  Stefan Roettger's CLOD algorithm.
//
// utilizes: Roettger's MINI library implementation
// http://wwwvis.informatik.uni-stuttgart.de/~roettger
//
// Copyright (c) 2002-2005 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "vtlib/vtlib.h"
#include "SRTerrain.h"
#include "vtdata/vtLog.h"

#if VTLIB_NI
// stub
SRTerrain::SRTerrain() {}
SRTerrain::~SRTerrain() {}
float SRTerrain::GetElevation(int iX, int iZ, bool bTrue) const { return 0; }
void SRTerrain::GetWorldLocation(int i, int j, FPoint3 &p, bool bTrue) const {}
void SRTerrain::DoCulling(const vtCamera *pCam) {}
void SRTerrain::DoRender() {}
void SRTerrain::SetVerticalExag(float fExag) {}
DTErr SRTerrain::Init(const vtElevationGrid *pGrid, float fZScale) { return DTErr_NOMEM; }
#else

#include "mini.h"
#include "ministub.hpp"

using namespace mini;
#ifdef _MSC_VER
// Set the following "1" to "0" before each code release, because non-core
//	developers don't need to debug into the libMini library, so they won't
//  need the *d version.
#if _DEBUG && 0
#pragma message( "Adding link with libMinid.lib" )
#pragma comment( lib, "libMinid.lib" )
#else
#pragma message( "Adding link with libMini.lib" )
#pragma comment( lib, "libMini.lib" )
#endif
#endif

/////////////////////////////////////////////////////////////////////////////

//
// Constructor/destructor
//
SRTerrain::SRTerrain() : vtDynTerrainGeom()
{
	m_fResolution	= 10000.0f;
	m_fHResolution	= 20000.0f;
	m_fLResolution	=     0.0f;
	m_pMini = NULL;
}

SRTerrain::~SRTerrain()
{
	if (m_pMini)
	{
		delete m_pMini;
		m_pMini = NULL;
	}
}

/////////////////////////////////////////////////////////////////////////////

//
// Unfortunately the following statics are required because libMini only
// supports some functionality by callback, and the callback is only a
// simple C function which has no context to tell us which terrain.
//
static const vtElevationGrid *s_pGrid;
static SRTerrain *s_pSRTerrain;
static int myfancnt, myvtxcnt;
static int s_iRows;

void beginfan_vtp()
{
	if (myfancnt++>0)
		glEnd();
	glBegin(GL_TRIANGLE_FAN);
	myvtxcnt-=2;	// 2 vertices are needed to start each fan
}

void fanvertex_vtp(float x, float y, float z)
{
	glVertex3f(x,y,z);
	myvtxcnt++;
}

void notify_vtp(int i, int j, int size)
{
	// check to see if we need to switch texture
	if (s_pSRTerrain->m_iTPatchDim > 1 && size == s_pSRTerrain->m_iBlockSize)
	{
		int a = i / size;
		int b = j / size;
		s_pSRTerrain->LoadBlockMaterial(a, b);
	}
}

short int getelevation_vtp1(int i, int j, int size, void *data_unused)
{
	return s_pGrid->GetValue(i, s_iRows-1-j);
}

float getelevation_vtp2(int i, int j, int size, void *data_unused)
{
	return s_pGrid->GetFValue(i, s_iRows-1-j);
}

//
// Initialize the terrain data
// fZScale converts from height values (meters) to world coordinates
//
DTErr SRTerrain::Init(const vtElevationGrid *pGrid, float fZScale)
{
	// Initializes necessary field of the parent class
	DTErr err = BasicInit(pGrid);
	if (err != DTErr_OK)
		return err;

	if (m_iColumns != m_iRows)
		return DTErr_NOTSQUARE;

	// compute n (log2 of grid size)
	// ensure that the grid is size (1 << n) + 1
	int n = vt_log2(m_iColumns - 1);
	int required_size = (1<<n) + 1;
	if (m_iColumns != required_size || m_iRows != required_size)
		return DTErr_NOTPOWER2;

	int size = m_iColumns;
	float dim = m_fXStep;
	float cellaspect = m_fZStep / m_fXStep;

	s_pGrid = pGrid;
	s_iRows = m_iRows;

#if 0
	// NOTE: the following workaround is no longer needed with libMini 5.02
	//
	// Totally strange but repeatable behavior: runtime exit in Release-mode
	//  libMini with values over a certain level.  Workaround here!
	// Exit happens if (scale * maximum_height / dim > 967)
	//
	// 	scale * maximum_height / dim > 967
	//	scale > dim * 967 / maximum_height
	//
	float fMin, fMax;
	pGrid->GetHeightExtents(fMin, fMax);
	// Avoid trouble with fMax small or zero
	if (fMax < 10) fMax = 10;
	// compute the largest supported value for MaxScale
	float fMaxMax = dim * 960 / fMax;
	// values greater than 10 are unnecessarily large
	if (fMaxMax > 10)
		fMaxMax = 10;
	m_fMaximumScale = fMaxMax;
#else
	// This maxiumum scale is a reasonable tradeoff between the exaggeration
	//  that the user is likely to need, and numerical precision issues.
	m_fMaximumScale = 10;
#endif

	m_fHeightScale = fZScale;
	m_fDrawScale = m_fHeightScale / m_fMaximumScale;

	if (pGrid->IsFloatMode())
	{
		float *image = NULL;
		m_pMini = new ministub(image,
				&size, &dim, m_fMaximumScale, cellaspect,
				0.0f, 0.0f, 0.0f,	// grid center
				beginfan_vtp, fanvertex_vtp, notify_vtp,
				getelevation_vtp2);
	}
	else
	{
		short *image = NULL;
		m_pMini = new ministub(image,
				&size, &dim, m_fMaximumScale, cellaspect,
				0.0f, 0.0f, 0.0f,	// grid center
				beginfan_vtp, fanvertex_vtp, notify_vtp,
				getelevation_vtp1);
	}

	m_iDrawnTriangles = -1;
	m_iBlockSize = m_iColumns / 4;

	return DTErr_OK;
}

void SRTerrain::SetVerticalExag(float fExag)
{
	m_fHeightScale = fExag;

	// safety check
	if (m_fHeightScale > m_fMaximumScale)
		m_fHeightScale = m_fMaximumScale;

	m_fDrawScale = m_fHeightScale / m_fMaximumScale;
}

//
// This will be called once per frame, during the culling pass.
//
// However, libMini does not allow you to call the culling pass
// independently of the rendering pass, so we cannot do culling here.
// Instead, just store the values for later use.
//
void SRTerrain::DoCulling(const vtCamera *pCam)
{
	// Grab necessary values from the VTP Scene framework, store for later
	m_eyepos_ogl = pCam->GetTrans();
	m_window_size = vtGetScene()->GetWindowSize();
	m_fAspect = (float)m_window_size.x / m_window_size.y;
	m_fNear = pCam->GetHither();
	m_fFar = pCam->GetYon();

	// Get up vector and direction vector from camera matrix
	FMatrix4 mat;
	pCam->GetTransform1(mat);
	FPoint3 up(0.0f, 1.0f, 0.0f);
	mat.TransformVector(up, eye_up);

	FPoint3 forward(0.0f, 0.0f, -1.0f);
	mat.TransformVector(forward, eye_forward);

	if (pCam->IsOrtho())
	{
		// libMini supports orthographic viewing as of libMini 5.0.
		// A negative FOV value indicates to the library that the FOV is
		//  actually the orthographic height of the camera.
		m_fFOVY = pCam->GetWidth() / m_fAspect;
		m_fFOVY = -m_fFOVY;
	}
	else
	{
		float fov = pCam->GetFOV();
		float fov_y2 = atan(tan (fov/2) / m_fAspect);
		m_fFOVY = fov_y2 * 2.0f * 180 / PIf;
	}
}

void SRTerrain::DoRender()
{
	// Prepare the render state for our OpenGL usage
	PreRender();

	// Render the triangles
	RenderSurface();

	// Clean up
	PostRender();
}

void SRTerrain::LoadSingleMaterial()
{
	// single texture for the whole terrain
	vtMaterial *pMat = GetMaterial(0);
	if (pMat)
	{
		pMat->Apply();
		SetupTexGen(1.0f);
	}
}

void SRTerrain::LoadBlockMaterial(int a, int b)
{
	// we can't change the texture between glBegin/glEnd
	if (myfancnt++>0)
		glEnd();

	// each block has it's own texture map
	int matidx = a*m_iTPatchDim + (m_iTPatchDim-1-b);
	vtMaterial *pMat = GetMaterial(matidx);
	if (pMat)
	{
		pMat->Apply();
		SetupBlockTexGen(a, b);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	}

	glBegin(GL_TRIANGLE_FAN);
}

void SRTerrain::RenderSurface()
{
	s_pSRTerrain = this;

	if (m_iTPatchDim == 1)
		LoadSingleMaterial();

	RenderPass();

	// how to do a second rendering pass
	if (m_bDetailTexture)
	{
		// once again, with the detail texture material
		m_pDetailMat->Apply();

		// the uv tiling is different (usually highly repetitive)
		SetupTexGen(m_fDetailTiling);

		// draw the second pass
		glPolygonOffset(-1.0f, -1.0f);
		glEnable(GL_POLYGON_OFFSET_FILL);
		RenderPass();
		glDisable(GL_POLYGON_OFFSET_FILL);
	}
	DisableTexGen();
}

void SRTerrain::RenderPass()
{
	float ex = m_eyepos_ogl.x;
	float ey = m_eyepos_ogl.y;
	float ez = m_eyepos_ogl.z;

	float fov = m_fFOVY;

	float ux = eye_up.x;
	float uy = eye_up.y;
	float uz = eye_up.z;

	float dx = eye_forward.x;
	float dy = eye_forward.y;
	float dz = eye_forward.z;

	myfancnt = myvtxcnt = 0;

	// Convert the eye location to the unusual coordinate scheme of libMini.
	ex -= (m_iColumns/2)*m_fXStep;
	ez += (m_iRows/2)*m_fZStep;

	m_pMini->draw(m_fResolution,
				ex, ey, ez,
				dx, dy, dz,
				ux, uy, uz,
				fov, m_fAspect,
				m_fNear, m_fFar,
				m_fDrawScale);

	if (myfancnt>0) glEnd();

	// We are drawing fans, so the number of triangles is roughly equal to
	// number of vertices
	m_iDrawnTriangles = myvtxcnt;

	// adaptively adjust resolution threshold up or down to attain
	// the desired polygon (vertex) count target
	int diff = m_iDrawnTriangles - m_iPolygonTarget;
	int iRange = m_iPolygonTarget / 10;		// ensure within 10%

	// If we aren't within the triangle count range adjust the input resolution
	// like a binary search
	if (diff < -iRange || diff > iRange)
	{
//		VTLOG("diff %d, ", diff);
		if (diff < -iRange)
		{
			m_fLResolution = m_fResolution;

			// if the high end isn't high enough, double it
			if (m_fLResolution + 5 >= m_fHResolution)
			{
//				VTLOG("increase HRes, ");
				m_fHResolution *= 10;
			}
		}
		else
		{
			m_fHResolution = m_fResolution;
			if (m_fLResolution + 5 >= m_fHResolution)
			{
//				VTLOG("decrease LRes, ");
				m_fLResolution = 0;
			}
		}

		m_fResolution = m_fLResolution + (m_fHResolution - m_fLResolution) / 2;
//		VTLOG("rez: [%.1f, %.1f, %.1f] (%d/%d)\n", m_fLResolution, m_fResolution, m_fHResolution, m_iDrawnTriangles, m_iPolygonTarget);

		// keep the error within reasonable bounds
		if (m_fResolution < 5.0f)
			m_fResolution = 5.0f;
		if (m_fResolution > 4E7)
			m_fResolution = 4E7;
	}
}

//
// These methods are called when the framework needs to know the surface
// position of the terrain at a given grid point.  Supply the height
// value from our own data structures.
//
float SRTerrain::GetElevation(int iX, int iZ, bool bTrue) const
{
	float height = m_pMini->getheight(iX, iZ);

	if (iX<0 || iX>m_iColumns-1 || iZ<0 || iZ>m_iRows-1)
		return 0.0f;

	if (bTrue)
		// convert stored value to true value
		return height / m_fMaximumScale;
	else
		// convert stored value to drawn value
		return height * m_fDrawScale;
}

void SRTerrain::GetWorldLocation(int i, int j, FPoint3 &p, bool bTrue) const
{
	float height = m_pMini->getheight(i, j);

	if (bTrue)
		// convert stored value to true value
		height /= m_fMaximumScale;
	else
		// convert stored value to drawn value
		height *= m_fDrawScale;

	p.Set(m_fXLookup[i],
		  height,
		  m_fZLookup[j]);
}
void SRTerrain::SetPolygonCount(int iPolygonCount)
{
	vtDynTerrainGeom::SetPolygonCount(iPolygonCount);
	m_fResolution = iPolygonCount * 5;
	m_fHResolution = 2 * m_fResolution;
	m_fLResolution = 0;
}

#endif	// VTLIB_NI
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2013-2016.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "acpica.hpp"
#include "acpi.hpp"
#include "kernel_utils.hpp"
#include "timer.hpp"
#include "paging.hpp"
#include "console.hpp"
#include "logging.hpp"
#include "scheduler.hpp"
#include "arch.hpp"

namespace {

// This is copied from acexcep.h
// This could be used with ACPI_DEFINE_EXCEPTION_TABLE but this
// generates too many warnings and errors

static const ACPI_EXCEPTION_INFO AcpiGbl_ExceptionNames_Env[] = {
    EXCEP_TXT ("AE_OK",                         "No error"),
    EXCEP_TXT ("AE_ERROR",                      "Unspecified error"),
    EXCEP_TXT ("AE_NO_ACPI_TABLES",             "ACPI tables could not be found"),
    EXCEP_TXT ("AE_NO_NAMESPACE",               "A namespace has not been loaded"),
    EXCEP_TXT ("AE_NO_MEMORY",                  "Insufficient dynamic memory"),
    EXCEP_TXT ("AE_NOT_FOUND",                  "A requested entity is not found"),
    EXCEP_TXT ("AE_NOT_EXIST",                  "A required entity does not exist"),
    EXCEP_TXT ("AE_ALREADY_EXISTS",             "An entity already exists"),
    EXCEP_TXT ("AE_TYPE",                       "The object type is incorrect"),
    EXCEP_TXT ("AE_NULL_OBJECT",                "A required object was missing"),
    EXCEP_TXT ("AE_NULL_ENTRY",                 "The requested object does not exist"),
    EXCEP_TXT ("AE_BUFFER_OVERFLOW",            "The buffer provided is too small"),
    EXCEP_TXT ("AE_STACK_OVERFLOW",             "An internal stack overflowed"),
    EXCEP_TXT ("AE_STACK_UNDERFLOW",            "An internal stack underflowed"),
    EXCEP_TXT ("AE_NOT_IMPLEMENTED",            "The feature is not implemented"),
    EXCEP_TXT ("AE_SUPPORT",                    "The feature is not supported"),
    EXCEP_TXT ("AE_LIMIT",                      "A predefined limit was exceeded"),
    EXCEP_TXT ("AE_TIME",                       "A time limit or timeout expired"),
    EXCEP_TXT ("AE_ACQUIRE_DEADLOCK",           "Internal error, attempt was made to acquire a mutex in improper order"),
    EXCEP_TXT ("AE_RELEASE_DEADLOCK",           "Internal error, attempt was made to release a mutex in improper order"),
    EXCEP_TXT ("AE_NOT_ACQUIRED",               "An attempt to release a mutex or Global Lock without a previous acquire"),
    EXCEP_TXT ("AE_ALREADY_ACQUIRED",           "Internal error, attempt was made to acquire a mutex twice"),
    EXCEP_TXT ("AE_NO_HARDWARE_RESPONSE",       "Hardware did not respond after an I/O operation"),
    EXCEP_TXT ("AE_NO_GLOBAL_LOCK",             "There is no FACS Global Lock"),
    EXCEP_TXT ("AE_ABORT_METHOD",               "A control method was aborted"),
    EXCEP_TXT ("AE_SAME_HANDLER",               "Attempt was made to install the same handler that is already installed"),
    EXCEP_TXT ("AE_NO_HANDLER",                 "A handler for the operation is not installed"),
    EXCEP_TXT ("AE_OWNER_ID_LIMIT",             "There are no more Owner IDs available for ACPI tables or control methods"),
    EXCEP_TXT ("AE_NOT_CONFIGURED",             "The interface is not part of the current subsystem configuration"),
    EXCEP_TXT ("AE_ACCESS",                     "Permission denied for the requested operation"),
    EXCEP_TXT ("AE_IO_ERROR",                   "An I/O error occurred")
};

volatile bool acpi_initialized = false;

void initialize_acpica(){
    logging::logf(logging::log_level::DEBUG, "acpi:: Started initialization of ACPICA\n");

    /* Initialize the ACPICA subsystem */

    auto status = AcpiInitializeSubsystem();
    if(ACPI_FAILURE(status)){
        logging::logf(logging::log_level::ERROR, "acpica: Impossible to initialize subsystem: error: %s\n", AcpiGbl_ExceptionNames_Env[status].Name);
        return;
    }

    /* Initialize the ACPICA Table Manager and get all ACPI tables */

    status = AcpiInitializeTables(nullptr, 16, FALSE);
    if (ACPI_FAILURE (status)){
        logging::logf(logging::log_level::ERROR, "acpica: Impossible to initialize tables: error: %s\n", AcpiGbl_ExceptionNames_Env[status].Name);
        return;
    }

    /* Create the ACPI namespace from ACPI tables */

    status = AcpiLoadTables ();
    if (ACPI_FAILURE (status)){
        logging::logf(logging::log_level::ERROR, "acpica: Impossible to load tables: error: %s\n", AcpiGbl_ExceptionNames_Env[status].Name);
        return;
    }

    /* Initialize the ACPI hardware */

    status = AcpiEnableSubsystem (ACPI_FULL_INITIALIZATION);
    if (ACPI_FAILURE (status)){
        logging::logf(logging::log_level::ERROR, "acpica: Impossible to enable subsystem: error: %s\n", AcpiGbl_ExceptionNames_Env[status].Name);
        return;
    }

    /* Complete the ACPI namespace object initialization */

    status = AcpiInitializeObjects (ACPI_FULL_INITIALIZATION);
    if (ACPI_FAILURE (status)){
        logging::logf(logging::log_level::ERROR, "acpica: Impossible to initialize objects: error: %s\n", AcpiGbl_ExceptionNames_Env[status].Name);
        return;
    }

    acpi_initialized = true;

    logging::logf(logging::log_level::DEBUG, "acpi:: Finished initialization of ACPICA\n");
}

} //end of anonymous namespace

void acpi::init(){
    // ACPICA needs scheduling to be started
    scheduler::queue_async_init_task(initialize_acpica);
}

void acpi::shutdown(){
    auto status = AcpiEnterSleepStatePrep(5);

    if(ACPI_FAILURE(status)){
        logging::logf(logging::log_level::ERROR, "acpica: Impossible to prepare sleep state: error: %s\n", AcpiGbl_ExceptionNames_Env[status].Name);
        return;
    }

    size_t rflags;
    arch::disable_hwint(rflags);
    status = AcpiEnterSleepState(5);

    if(ACPI_FAILURE(status)){
        logging::logf(logging::log_level::ERROR, "acpica: Impossible to enter sleep state: error: %s\n", AcpiGbl_ExceptionNames_Env[status].Name);
        return;
    }

    k_print_line("acpi poweroff failed.");
    arch::enable_hwint(rflags);
}

bool acpi::initialized(){
    return acpi_initialized;
}
<commit_msg>Allow resizing of ACPI tables<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2013-2016.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "acpica.hpp"
#include "acpi.hpp"
#include "kernel_utils.hpp"
#include "timer.hpp"
#include "paging.hpp"
#include "console.hpp"
#include "logging.hpp"
#include "scheduler.hpp"
#include "arch.hpp"

namespace {

// This is copied from acexcep.h
// This could be used with ACPI_DEFINE_EXCEPTION_TABLE but this
// generates too many warnings and errors

static const ACPI_EXCEPTION_INFO AcpiGbl_ExceptionNames_Env[] = {
    EXCEP_TXT ("AE_OK",                         "No error"),
    EXCEP_TXT ("AE_ERROR",                      "Unspecified error"),
    EXCEP_TXT ("AE_NO_ACPI_TABLES",             "ACPI tables could not be found"),
    EXCEP_TXT ("AE_NO_NAMESPACE",               "A namespace has not been loaded"),
    EXCEP_TXT ("AE_NO_MEMORY",                  "Insufficient dynamic memory"),
    EXCEP_TXT ("AE_NOT_FOUND",                  "A requested entity is not found"),
    EXCEP_TXT ("AE_NOT_EXIST",                  "A required entity does not exist"),
    EXCEP_TXT ("AE_ALREADY_EXISTS",             "An entity already exists"),
    EXCEP_TXT ("AE_TYPE",                       "The object type is incorrect"),
    EXCEP_TXT ("AE_NULL_OBJECT",                "A required object was missing"),
    EXCEP_TXT ("AE_NULL_ENTRY",                 "The requested object does not exist"),
    EXCEP_TXT ("AE_BUFFER_OVERFLOW",            "The buffer provided is too small"),
    EXCEP_TXT ("AE_STACK_OVERFLOW",             "An internal stack overflowed"),
    EXCEP_TXT ("AE_STACK_UNDERFLOW",            "An internal stack underflowed"),
    EXCEP_TXT ("AE_NOT_IMPLEMENTED",            "The feature is not implemented"),
    EXCEP_TXT ("AE_SUPPORT",                    "The feature is not supported"),
    EXCEP_TXT ("AE_LIMIT",                      "A predefined limit was exceeded"),
    EXCEP_TXT ("AE_TIME",                       "A time limit or timeout expired"),
    EXCEP_TXT ("AE_ACQUIRE_DEADLOCK",           "Internal error, attempt was made to acquire a mutex in improper order"),
    EXCEP_TXT ("AE_RELEASE_DEADLOCK",           "Internal error, attempt was made to release a mutex in improper order"),
    EXCEP_TXT ("AE_NOT_ACQUIRED",               "An attempt to release a mutex or Global Lock without a previous acquire"),
    EXCEP_TXT ("AE_ALREADY_ACQUIRED",           "Internal error, attempt was made to acquire a mutex twice"),
    EXCEP_TXT ("AE_NO_HARDWARE_RESPONSE",       "Hardware did not respond after an I/O operation"),
    EXCEP_TXT ("AE_NO_GLOBAL_LOCK",             "There is no FACS Global Lock"),
    EXCEP_TXT ("AE_ABORT_METHOD",               "A control method was aborted"),
    EXCEP_TXT ("AE_SAME_HANDLER",               "Attempt was made to install the same handler that is already installed"),
    EXCEP_TXT ("AE_NO_HANDLER",                 "A handler for the operation is not installed"),
    EXCEP_TXT ("AE_OWNER_ID_LIMIT",             "There are no more Owner IDs available for ACPI tables or control methods"),
    EXCEP_TXT ("AE_NOT_CONFIGURED",             "The interface is not part of the current subsystem configuration"),
    EXCEP_TXT ("AE_ACCESS",                     "Permission denied for the requested operation"),
    EXCEP_TXT ("AE_IO_ERROR",                   "An I/O error occurred")
};

volatile bool acpi_initialized = false;

void initialize_acpica(){
    logging::logf(logging::log_level::DEBUG, "acpi:: Started initialization of ACPICA\n");

    /* Initialize the ACPICA subsystem */

    auto status = AcpiInitializeSubsystem();
    if(ACPI_FAILURE(status)){
        logging::logf(logging::log_level::ERROR, "acpica: Impossible to initialize subsystem: error: %s\n", AcpiGbl_ExceptionNames_Env[status].Name);
        return;
    }

    /* Initialize the ACPICA Table Manager and get all ACPI tables */

    status = AcpiInitializeTables(nullptr, 16, true);
    if (ACPI_FAILURE (status)){
        logging::logf(logging::log_level::ERROR, "acpica: Impossible to initialize tables: error: %s\n", AcpiGbl_ExceptionNames_Env[status].Name);
        return;
    }

    /* Create the ACPI namespace from ACPI tables */

    status = AcpiLoadTables ();
    if (ACPI_FAILURE (status)){
        logging::logf(logging::log_level::ERROR, "acpica: Impossible to load tables: error: %s\n", AcpiGbl_ExceptionNames_Env[status].Name);
        return;
    }

    /* Initialize the ACPI hardware */

    status = AcpiEnableSubsystem (ACPI_FULL_INITIALIZATION);
    if (ACPI_FAILURE (status)){
        logging::logf(logging::log_level::ERROR, "acpica: Impossible to enable subsystem: error: %s\n", AcpiGbl_ExceptionNames_Env[status].Name);
        return;
    }

    /* Complete the ACPI namespace object initialization */

    status = AcpiInitializeObjects (ACPI_FULL_INITIALIZATION);
    if (ACPI_FAILURE (status)){
        logging::logf(logging::log_level::ERROR, "acpica: Impossible to initialize objects: error: %s\n", AcpiGbl_ExceptionNames_Env[status].Name);
        return;
    }

    acpi_initialized = true;

    logging::logf(logging::log_level::DEBUG, "acpi:: Finished initialization of ACPICA\n");
}

} //end of anonymous namespace

void acpi::init(){
    // ACPICA needs scheduling to be started
    scheduler::queue_async_init_task(initialize_acpica);
}

void acpi::shutdown(){
    auto status = AcpiEnterSleepStatePrep(5);

    if(ACPI_FAILURE(status)){
        logging::logf(logging::log_level::ERROR, "acpica: Impossible to prepare sleep state: error: %s\n", AcpiGbl_ExceptionNames_Env[status].Name);
        return;
    }

    size_t rflags;
    arch::disable_hwint(rflags);
    status = AcpiEnterSleepState(5);

    if(ACPI_FAILURE(status)){
        logging::logf(logging::log_level::ERROR, "acpica: Impossible to enter sleep state: error: %s\n", AcpiGbl_ExceptionNames_Env[status].Name);
        return;
    }

    k_print_line("acpi poweroff failed.");
    arch::enable_hwint(rflags);
}

bool acpi::initialized(){
    return acpi_initialized;
}
<|endoftext|>


<commit_before>/* Copyright 2019 Andrei Khodko
 *
 * 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
 *
 * 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 "utilities.h"

#include "QsLog.h"

QImage Utilities::imageFromBytes(const QVector<int32_t> &array, int width, int height, const QString &format){
	auto fmt = QImage::Format_RGB32;
	auto *rawData = static_cast<const uchar *>(static_cast<const void *>(array.data()));

	// Reserve maximum possible size to avoid reallocation
	auto formattedData  = new uchar[(width + 3) * (height + 3) * 3 + 3];
	static auto cleanUp = [](void *p) { if (p) delete [](static_cast<decltype (formattedData)>(p)); };
	void *cleanUpInfo = nullptr;

	// QImage requires 32-bit aligned scan lines
	// Helper function to convert data
	auto copyAligned = [&](int perLine){
		auto scanLineSize = static_cast<int>((static_cast<unsigned>(perLine + 3)) & 0xFFFFFFFC);
		auto dst = formattedData;
		for (auto src = array.begin(); src < array.end(); src += perLine) {
			dst = std::copy(src, src + perLine, dst);
			dst += scanLineSize - perLine;
		}
		rawData = formattedData;
		cleanUpInfo = formattedData;
	};

	if (!format.compare("rgb32", Qt::CaseInsensitive)) {
		/* do nothing */
	} else if (!format.compare("rgb888", Qt::CaseInsensitive)) {
		fmt = QImage::Format_RGB888;
		copyAligned(3 * width);
	} else if (format == "grayscale8") {
		fmt = QImage::Format_Grayscale8;
		copyAligned(width);
	} else {
		QLOG_ERROR() << "Unsupported format " << format;
		return QImage();
	}

	return QImage(rawData, width, height, fmt, cleanUp, cleanUpInfo);
}
<commit_msg>Fix showing uninialized data from failed getPhoto()<commit_after>/* Copyright 2019 Andrei Khodko
 *
 * 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
 *
 * 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 "utilities.h"

#include "QsLog.h"

QImage Utilities::imageFromBytes(const QVector<int32_t> &array, int width, int height, const QString &format){

	if (array.empty()) {
		return QImage();
	}

	auto fmt = QImage::Format_RGB32;
	auto *rawData = static_cast<const uchar *>(static_cast<const void *>(array.data()));

	// Reserve maximum possible size to avoid reallocation
	auto formattedData  = new uchar[(width + 3) * (height + 3) * 3 + 3];
	static auto cleanUp = [](void *p) { if (p) delete [](static_cast<decltype (formattedData)>(p)); };
	void *cleanUpInfo = nullptr;

	// QImage requires 32-bit aligned scan lines
	// Helper function to convert data
	auto copyAligned = [&](int perLine){
		auto scanLineSize = static_cast<int>((static_cast<unsigned>(perLine + 3)) & 0xFFFFFFFC);
		auto dst = formattedData;
		for (auto src = array.begin(); src < array.end(); src += perLine) {
			dst = std::copy(src, src + perLine, dst);
			dst += scanLineSize - perLine;
		}
		rawData = formattedData;
		cleanUpInfo = formattedData;
	};

	if (!format.compare("rgb32", Qt::CaseInsensitive)) {
		/* do nothing */
	} else if (!format.compare("rgb888", Qt::CaseInsensitive)) {
		fmt = QImage::Format_RGB888;
		copyAligned(3 * width);
	} else if (format == "grayscale8") {
		fmt = QImage::Format_Grayscale8;
		copyAligned(width);
	} else {
		QLOG_ERROR() << "Unsupported format " << format;
		return QImage();
	}

	return QImage(rawData, width, height, fmt, cleanUp, cleanUpInfo);
}
<|endoftext|>


<commit_before>/*
 Arduino.cpp - Mocks for common Arduino APIs
 Copyright © 2016 Ivan Grokhotkov

 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.
*/

#include <sys/time.h>
#include "Arduino.h"

#include <unistd.h>

extern "C" unsigned long millis()
{
    timeval time;
    gettimeofday(&time, NULL);
    return (time.tv_sec * 1000) + (time.tv_usec / 1000);
}

extern "C" unsigned long micros()
{
    timeval time;
    gettimeofday(&time, NULL);
    return (time.tv_sec * 1000000) + time.tv_usec;
}

extern "C" void yield()
{
}

extern "C" bool can_yield()
{
    return true;
}

extern "C" void optimistic_yield (uint32_t interval_us)
{
    usleep(interval_us);
}

extern "C" void esp_yield()
{
}

extern "C" void __panic_func(const char* file, int line, const char* func) {
    (void)file;
    (void)line;
    (void)func;
    abort();
}

extern "C" void delay(unsigned long ms)
{
    usleep(ms * 1000);
}

extern "C" void delayMicroseconds(unsigned int us)
{
    usleep(us);
}

#include "cont.h"
cont_t* g_pcont = NULL;
extern "C" void cont_yield(cont_t*)
{
}

<commit_msg>host build: optimistic_yield() wrongly delays() instead of avoiding excessive yields (#6802)<commit_after>/*
 Arduino.cpp - Mocks for common Arduino APIs
 Copyright © 2016 Ivan Grokhotkov

 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.
*/

#include <sys/time.h>
#include "Arduino.h"

#include <unistd.h>

extern "C" unsigned long millis()
{
    timeval time;
    gettimeofday(&time, NULL);
    return (time.tv_sec * 1000) + (time.tv_usec / 1000);
}

extern "C" unsigned long micros()
{
    timeval time;
    gettimeofday(&time, NULL);
    return (time.tv_sec * 1000000) + time.tv_usec;
}

extern "C" void yield()
{
}

extern "C" bool can_yield()
{
    return true;
}

extern "C" void optimistic_yield (uint32_t interval_us)
{
    (void)interval_us;
}

extern "C" void esp_yield()
{
}

extern "C" void __panic_func(const char* file, int line, const char* func) {
    (void)file;
    (void)line;
    (void)func;
    abort();
}

extern "C" void delay(unsigned long ms)
{
    usleep(ms * 1000);
}

extern "C" void delayMicroseconds(unsigned int us)
{
    usleep(us);
}

#include "cont.h"
cont_t* g_pcont = NULL;
extern "C" void cont_yield(cont_t*)
{
}

<|endoftext|>


<commit_before>// Scintilla source code edit control
/** @file KeyWords.cxx
 ** Colourise for particular languages.
 **/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

LexerModule *LexerModule::base = 0;
int LexerModule::nextLanguage = SCLEX_AUTOMATIC+1;

LexerModule::LexerModule(int language_, LexerFunction fnLexer_,
	const char *languageName_, LexerFunction fnFolder_) :
	language(language_),
	languageName(languageName_),
	fnLexer(fnLexer_),
	fnFolder(fnFolder_) {
	next = base;
	base = this;
	if (language == SCLEX_AUTOMATIC) {
		language = nextLanguage;
		nextLanguage++;
	}
}

LexerModule *LexerModule::Find(int language) {
	LexerModule *lm = base;
	while (lm) {
		if (lm->language == language) {
			return lm;
		}
		lm = lm->next;
	}
	return 0;
}

LexerModule *LexerModule::Find(const char *languageName) {
	if (languageName) {
		LexerModule *lm = base;
		while (lm) {
			if (lm->languageName && 0 == strcmp(lm->languageName, languageName)) {
				return lm;
			}
			lm = lm->next;
		}
	}
	return 0;
}

void LexerModule::Lex(unsigned int startPos, int lengthDoc, int initStyle,
	  WordList *keywordlists[], Accessor &styler) {
	if (fnLexer)
		fnLexer(startPos, lengthDoc, initStyle, keywordlists, styler);
}

void LexerModule::Fold(unsigned int startPos, int lengthDoc, int initStyle,
	  WordList *keywordlists[], Accessor &styler) {
	if (fnFolder) {
		int lineCurrent = styler.GetLine(startPos);
		// Move back one line in case deletion wrecked current line fold state
		if (lineCurrent > 0) {
			lineCurrent--;
			int newStartPos = styler.LineStart(lineCurrent);
			lengthDoc += startPos - newStartPos;
			startPos = newStartPos;
			initStyle = 0;
			if (startPos > 0) {
				initStyle = styler.StyleAt(startPos - 1);
			}
		}
		fnFolder(startPos, lengthDoc, initStyle, keywordlists, styler);
	}
}

static void ColouriseNullDoc(unsigned int startPos, int length, int, WordList *[],
                            Accessor &styler) {
	// Null language means all style bytes are 0 so just mark the end - no need to fill in.
	if (length > 0) {
		styler.StartAt(startPos + length - 1);
		styler.StartSegment(startPos + length - 1);
		styler.ColourTo(startPos + length - 1, 0);
	}
}

LexerModule lmNull(SCLEX_NULL, ColouriseNullDoc, "null");

#ifdef __vms

// The following code forces a reference to all of the Scintilla lexers.
// If we don't do something like this, then the linker tends to "optimize"
// them away. (eric@sourcegear.com)

// Taken from wxWindow's stc.cpp. Walter.

int wxForceScintillaLexers(void) {
  extern LexerModule lmAda;
  extern LexerModule lmAVE;
  extern LexerModule lmBaan;
  extern LexerModule lmBatch;
  extern LexerModule lmConf;
  extern LexerModule lmCPP;
  extern LexerModule lmDiff;
  extern LexerModule lmEiffel;
  extern LexerModule lmEiffelkw;
  extern LexerModule lmErrorList;
  extern LexerModule lmHTML;
  extern LexerModule lmLatex;
  extern LexerModule lmLISP;
  extern LexerModule lmLua;
  extern LexerModule lmMake;
  extern LexerModule lmPascal;
  extern LexerModule lmPerl;
  extern LexerModule lmProps;
  extern LexerModule lmPython;
  extern LexerModule lmRuby;
  extern LexerModule lmSQL;
  extern LexerModule lmVB;
  extern LexerModule lmXML;
  extern LexerModule lmBullant;

  if (
      &lmAda
      && &lmAVE
      && &lmBaan
      && &lmConf
      && &lmDiff
      && &lmLatex
      && &lmPascal
      && &lmCPP
      && &lmHTML
      && &lmXML
      && &lmProps
      && &lmErrorList
      && &lmMake
      && &lmBatch
      && &lmPerl
      && &lmPython
      && &lmSQL
      && &lmVB
      && &lmRuby
      && &lmEiffel
      && &lmEiffelkw
      && &lmLISP
      && &lmLua
      && &lmNull
      && &lmBullant
      )
    {
      return 1;
    }
  else
    {
      return 0;
    }
}
#endif
<commit_msg>Changed preprocessor switch for compiling in lexer linking code to be LINK_LEXERS and if __vms is defined then LINK_LEXERS is defined. Scintilla_LinkLexers is a new name for wxForceScintillaLexers although the old name is still available.<commit_after>// Scintilla source code edit control
/** @file KeyWords.cxx
 ** Colourise for particular languages.
 **/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

LexerModule *LexerModule::base = 0;
int LexerModule::nextLanguage = SCLEX_AUTOMATIC+1;

LexerModule::LexerModule(int language_, LexerFunction fnLexer_,
	const char *languageName_, LexerFunction fnFolder_) :
	language(language_),
	languageName(languageName_),
	fnLexer(fnLexer_),
	fnFolder(fnFolder_) {
	next = base;
	base = this;
	if (language == SCLEX_AUTOMATIC) {
		language = nextLanguage;
		nextLanguage++;
	}
}

LexerModule *LexerModule::Find(int language) {
	LexerModule *lm = base;
	while (lm) {
		if (lm->language == language) {
			return lm;
		}
		lm = lm->next;
	}
	return 0;
}

LexerModule *LexerModule::Find(const char *languageName) {
	if (languageName) {
		LexerModule *lm = base;
		while (lm) {
			if (lm->languageName && 0 == strcmp(lm->languageName, languageName)) {
				return lm;
			}
			lm = lm->next;
		}
	}
	return 0;
}

void LexerModule::Lex(unsigned int startPos, int lengthDoc, int initStyle,
	  WordList *keywordlists[], Accessor &styler) {
	if (fnLexer)
		fnLexer(startPos, lengthDoc, initStyle, keywordlists, styler);
}

void LexerModule::Fold(unsigned int startPos, int lengthDoc, int initStyle,
	  WordList *keywordlists[], Accessor &styler) {
	if (fnFolder) {
		int lineCurrent = styler.GetLine(startPos);
		// Move back one line in case deletion wrecked current line fold state
		if (lineCurrent > 0) {
			lineCurrent--;
			int newStartPos = styler.LineStart(lineCurrent);
			lengthDoc += startPos - newStartPos;
			startPos = newStartPos;
			initStyle = 0;
			if (startPos > 0) {
				initStyle = styler.StyleAt(startPos - 1);
			}
		}
		fnFolder(startPos, lengthDoc, initStyle, keywordlists, styler);
	}
}

static void ColouriseNullDoc(unsigned int startPos, int length, int, WordList *[],
                            Accessor &styler) {
	// Null language means all style bytes are 0 so just mark the end - no need to fill in.
	if (length > 0) {
		styler.StartAt(startPos + length - 1);
		styler.StartSegment(startPos + length - 1);
		styler.ColourTo(startPos + length - 1, 0);
	}
}

LexerModule lmNull(SCLEX_NULL, ColouriseNullDoc, "null");

#ifdef __vms
#define LINK_LEXERS
#endif

#ifdef LINK_LEXERS

// The following code forces a reference to all of the Scintilla lexers.
// If we don't do something like this, then the linker tends to "optimize"
// them away. (eric@sourcegear.com)

// Taken from wxWindow's stc.cpp. Walter.

int wxForceScintillaLexers(void) {
	Scintilla_LinkLexers();
}

int Scintilla_LinkLexers() {
  extern LexerModule lmAda;
  extern LexerModule lmAVE;
  extern LexerModule lmBaan;
  extern LexerModule lmBatch;
  extern LexerModule lmConf;
  extern LexerModule lmCPP;
  extern LexerModule lmDiff;
  extern LexerModule lmEiffel;
  extern LexerModule lmEiffelkw;
  extern LexerModule lmErrorList;
  extern LexerModule lmHTML;
  extern LexerModule lmLatex;
  extern LexerModule lmLISP;
  extern LexerModule lmLua;
  extern LexerModule lmMake;
  extern LexerModule lmPascal;
  extern LexerModule lmPerl;
  extern LexerModule lmProps;
  extern LexerModule lmPython;
  extern LexerModule lmRuby;
  extern LexerModule lmSQL;
  extern LexerModule lmVB;
  extern LexerModule lmXML;
  extern LexerModule lmBullant;

  if (
      &lmAda
      && &lmAVE
      && &lmBaan
      && &lmConf
      && &lmDiff
      && &lmLatex
      && &lmPascal
      && &lmCPP
      && &lmHTML
      && &lmXML
      && &lmProps
      && &lmErrorList
      && &lmMake
      && &lmBatch
      && &lmPerl
      && &lmPython
      && &lmSQL
      && &lmVB
      && &lmRuby
      && &lmEiffel
      && &lmEiffelkw
      && &lmLISP
      && &lmLua
      && &lmNull
      && &lmBullant
      )
    {
      return 1;
    }
  else
    {
      return 0;
    }
}
#endif
<|endoftext|>


<commit_before>/******************************************************************************\
* File:          test.cpp
* Purpose:       Implementation for wxextension cpp unit testing
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
* Created:       za 17 jan 2009 11:51:20 CET
*
* Copyright (c) 2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <TestCaller.h>
#include "test.h"

void exTestFixture::setUp()
{
  m_File = new exFile("test.h");
  m_FileName = new exFileName("test.h");
  m_FileNameStatistics = new exFileNameStatistics("test.h");
  m_Lexer = new exLexer();
  m_RCS = new exRCS();
  m_Stat = new exStat("test.h");
  m_Statistics = new exStatistics<long>();
  m_Tool = new exTool(ID_TOOL_REPORT_COUNT);
}

void exTestFixture::testConstructors()
{
  CPPUNIT_ASSERT(m_File != NULL);
}

void exTestFixture::testMethods()
{
  // test exFile
  CPPUNIT_ASSERT(m_File->GetStat().IsOk());
  CPPUNIT_ASSERT(m_File->GetFileName().GetFullPath() == "test.h");

  // test exFileName
  CPPUNIT_ASSERT(m_FileName->GetStat().IsOk());

  // test exLexer
  m_Lexer->SetLexerFromText("// this is a cpp comment text");
  CPPUNIT_ASSERT(m_Lexer->GetScintillaLexer().empty()); // we have no lexers

  // test exRCS
  CPPUNIT_ASSERT(m_RCS->GetUser().empty());

  // test exStat
  CPPUNIT_ASSERT(m_Stat->IsOk());

  // test exStatistics
  m_Statistics->Inc("test");
  CPPUNIT_ASSERT(m_Statistics->Get("test") == 1);
  m_Statistics->Inc("test");
  CPPUNIT_ASSERT(m_Statistics->Get("test") == 2);
  m_Statistics->Set("test", 13);
  CPPUNIT_ASSERT(m_Statistics->Get("test") == 13);
  m_Statistics->Dec("test");
  CPPUNIT_ASSERT(m_Statistics->Get("test") == 12);
  m_Statistics->Inc("test2");
  CPPUNIT_ASSERT(m_Statistics->Get("test2") == 1);

  // test exTool
  CPPUNIT_ASSERT(m_Tool->IsStatisticsType() > 0);
}

void exTestFixture::testTiming()
{
  exFile file("test.h");

  CPPUNIT_ASSERT(file.IsOpened());

  wxStopWatch sw;

  const int max = 10000;

  for (int i = 0; i < max; i++)
  {
    wxString* buffer = file.Read();
    CPPUNIT_ASSERT(buffer ! NULL);
    delete buffer;
  }

  const long exfile_read = sw.Time();

  sw.Start();

  wxFile wxfile("test.h");

  for (int j = 0; j < max; j++)
  {
    char* charbuffer = new char[wxfile.Length()];
    wxfile.Read(charbuffer, wxfile.Length());
    wxString* buffer = new wxString(charbuffer, wxfile.Length());
    delete charbuffer;
    delete buffer;
  }

  const long file_read = sw.Time();

  printf(
    "exFile::Read:%ld wxFile::Read:%ld\n",
    exfile_read,
    file_read);
}

void exTestFixture::testTimingAttrib()
{
  const int max = 1000;

  wxStopWatch sw;

  const exFileName exfile("test.h");

  int checked = 0;

  for (int i = 0; i < max; i++)
  {
    checked += exfile.GetStat().IsReadOnly();
  }

  const long exfile_time = sw.Time();

  sw.Start();

  const wxFileName file("test.h");

  for (int j = 0; j < max; j++)
  {
    checked += file.IsFileWritable();
  }

  const long file_time = sw.Time();

  printf(
    "exFileName::IsReadOnly:%ld wxFileName::IsFileWritable:%ld\n",
    exfile_time,
    file_time);
}

void exTestFixture::tearDown()
{
}

void exAppTestFixture::setUp()
{
}

void exAppTestFixture::testConstructors()
{
  m_App = new exApp();
  m_Dir = new exDir("./");
  m_SVN = new exSVN(SVN_STAT, "test.h");
}

void exAppTestFixture::testMethods()
{
  // test exApp
  m_App->OnInit();

  CPPUNIT_ASSERT(m_App->GetConfig() != NULL);
  CPPUNIT_ASSERT(m_App->GetLexers() != NULL);
  CPPUNIT_ASSERT(m_App->GetPrinter() != NULL);

  // test exDir
  CPPUNIT_ASSERT(m_Dir->GetFiles().GetCount() > 0);

  // test exSVN
  m_SVN->Get();
}

void exAppTestFixture::testTimingConfig()
{
}

void exAppTestFixture::tearDown()
{
  const int max = 100000;

  wxStopWatch sw;

  for (int i = 0; i < max; i++)
  {
    exApp::GetConfig("test", 0);
  }

  const long exconfig = sw.Time();

  sw.Start();

  for (int j = 0; j < max; j++)
  {
    exApp::GetConfig()->Read("test", 0l);
  }

  const long config = sw.Time();

  printf(
    "exConfig::Get:%ld wxConfig::Read:%ld\n",
    exconfig,
    config);
  }
}

exTestSuite::exTestSuite()
  : CppUnit::TestSuite("wxextension test suite")

{
  // Add the tests.
  addTest(new CppUnit::TestCaller<exTestFixture>(
    "testConstructors",
    &exTestFixture::testConstructors));

  addTest(new CppUnit::TestCaller<exTestFixture>(
    "testMethods",
    &exTestFixture::testMethods));

  addTest(new CppUnit::TestCaller<exTestFixture>(
    "testTiming",
    &exTestFixture::testTiming));

  addTest(new CppUnit::TestCaller<exTestFixture>(
    "testTimingAttrib",
    &exTestFixture::testTimingAttrib));

/* TODO: the exApp or wxApp not yet okay without normal wxApp initialization

  addTest(new CppUnit::TestCaller<exAppTestFixture>(
    "testConstructors",
    &exAppTestFixture::testConstructors));

  addTest(new CppUnit::TestCaller<exAppTestFixture>(
    "testMethods",
    &exAppTestFixture::testMethods));

  addTest(new CppUnit::TestCaller<exAppTestFixture>(
    "testTimingConfig",
    &exAppTestFixture::testTimingConfig));
    */
}
<commit_msg>fixed error<commit_after>/******************************************************************************\
* File:          test.cpp
* Purpose:       Implementation for wxextension cpp unit testing
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
* Created:       za 17 jan 2009 11:51:20 CET
*
* Copyright (c) 2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <TestCaller.h>
#include "test.h"

void exTestFixture::setUp()
{
  m_File = new exFile("test.h");
  m_FileName = new exFileName("test.h");
  m_FileNameStatistics = new exFileNameStatistics("test.h");
  m_Lexer = new exLexer();
  m_RCS = new exRCS();
  m_Stat = new exStat("test.h");
  m_Statistics = new exStatistics<long>();
  m_Tool = new exTool(ID_TOOL_REPORT_COUNT);
}

void exTestFixture::testConstructors()
{
  CPPUNIT_ASSERT(m_File != NULL);
}

void exTestFixture::testMethods()
{
  // test exFile
  CPPUNIT_ASSERT(m_File->GetStat().IsOk());
  CPPUNIT_ASSERT(m_File->GetFileName().GetFullPath() == "test.h");

  // test exFileName
  CPPUNIT_ASSERT(m_FileName->GetStat().IsOk());

  // test exLexer
  m_Lexer->SetLexerFromText("// this is a cpp comment text");
  CPPUNIT_ASSERT(m_Lexer->GetScintillaLexer().empty()); // we have no lexers

  // test exRCS
  CPPUNIT_ASSERT(m_RCS->GetUser().empty());

  // test exStat
  CPPUNIT_ASSERT(m_Stat->IsOk());

  // test exStatistics
  m_Statistics->Inc("test");
  CPPUNIT_ASSERT(m_Statistics->Get("test") == 1);
  m_Statistics->Inc("test");
  CPPUNIT_ASSERT(m_Statistics->Get("test") == 2);
  m_Statistics->Set("test", 13);
  CPPUNIT_ASSERT(m_Statistics->Get("test") == 13);
  m_Statistics->Dec("test");
  CPPUNIT_ASSERT(m_Statistics->Get("test") == 12);
  m_Statistics->Inc("test2");
  CPPUNIT_ASSERT(m_Statistics->Get("test2") == 1);
  m_Statistics->Clear();
  CPPUNIT_ASSERT(m_Statistics->GetItems().empty());

  // test exTool
  CPPUNIT_ASSERT(m_Tool->IsStatisticsType() > 0);
}

void exTestFixture::testTiming()
{
  exFile file("test.h");

  CPPUNIT_ASSERT(file.IsOpened());

  wxStopWatch sw;

  const int max = 10000;

  for (int i = 0; i < max; i++)
  {
    wxString* buffer = file.Read();
    CPPUNIT_ASSERT(buffer != NULL);
    delete buffer;
  }

  const long exfile_read = sw.Time();

  sw.Start();

  wxFile wxfile("test.h");

  for (int j = 0; j < max; j++)
  {
    char* charbuffer = new char[wxfile.Length()];
    wxfile.Read(charbuffer, wxfile.Length());
    wxString* buffer = new wxString(charbuffer, wxfile.Length());
    delete charbuffer;
    delete buffer;
  }

  const long file_read = sw.Time();

  printf(
    "exFile::Read:%ld wxFile::Read:%ld\n",
    exfile_read,
    file_read);
}

void exTestFixture::testTimingAttrib()
{
  const int max = 1000;

  wxStopWatch sw;

  const exFileName exfile("test.h");

  int checked = 0;

  for (int i = 0; i < max; i++)
  {
    checked += exfile.GetStat().IsReadOnly();
  }

  const long exfile_time = sw.Time();

  sw.Start();

  const wxFileName file("test.h");

  for (int j = 0; j < max; j++)
  {
    checked += file.IsFileWritable();
  }

  const long file_time = sw.Time();

  printf(
    "exFileName::IsReadOnly:%ld wxFileName::IsFileWritable:%ld\n",
    exfile_time,
    file_time);
}

void exTestFixture::tearDown()
{
}

void exAppTestFixture::setUp()
{
}

void exAppTestFixture::testConstructors()
{
  m_App = new exApp();
  m_Dir = new exDir("./");
  m_SVN = new exSVN(SVN_STAT, "test.h");
}

void exAppTestFixture::testMethods()
{
  // test exApp
  m_App->OnInit();

  CPPUNIT_ASSERT(m_App->GetConfig() != NULL);
  CPPUNIT_ASSERT(m_App->GetLexers() != NULL);
  CPPUNIT_ASSERT(m_App->GetPrinter() != NULL);

  // test exDir
  CPPUNIT_ASSERT(m_Dir->GetFiles().GetCount() > 0);

  // test exSVN
  m_SVN->Get();
}

void exAppTestFixture::testTimingConfig()
{
  const int max = 100000;

  wxStopWatch sw;

  for (int i = 0; i < max; i++)
  {
    exApp::GetConfig("test", 0);
  }

  const long exconfig = sw.Time();

  sw.Start();

  for (int j = 0; j < max; j++)
  {
    exApp::GetConfig()->Read("test", 0l);
  }

  const long config = sw.Time();

  printf(
    "exConfig::Get:%ld wxConfig::Read:%ld\n",
    exconfig,
    config);
}

void exAppTestFixture::tearDown()
{
}

exTestSuite::exTestSuite()
  : CppUnit::TestSuite("wxextension test suite")

{
  // Add the tests.
  addTest(new CppUnit::TestCaller<exTestFixture>(
    "testConstructors",
    &exTestFixture::testConstructors));

  addTest(new CppUnit::TestCaller<exTestFixture>(
    "testMethods",
    &exTestFixture::testMethods));

  addTest(new CppUnit::TestCaller<exTestFixture>(
    "testTiming",
    &exTestFixture::testTiming));

  addTest(new CppUnit::TestCaller<exTestFixture>(
    "testTimingAttrib",
    &exTestFixture::testTimingAttrib));

/* TODO: the exApp or wxApp not yet okay without normal wxApp initialization

  addTest(new CppUnit::TestCaller<exAppTestFixture>(
    "testConstructors",
    &exAppTestFixture::testConstructors));

  addTest(new CppUnit::TestCaller<exAppTestFixture>(
    "testMethods",
    &exAppTestFixture::testMethods));

  addTest(new CppUnit::TestCaller<exAppTestFixture>(
    "testTimingConfig",
    &exAppTestFixture::testTimingConfig));
    */
}
<|endoftext|>