Ticket #5176: kenburns2.patch

File kenburns2.patch, 12.6 KB (added by joepadmiraal, 12 years ago)

Now compiles with current trunk (17120)

  • mythgallery/glsingleview.cpp

     
    9393      // Unshared effect state variables
    9494      m_effect_cube_xrot(0.0f),
    9595      m_effect_cube_yrot(0.0f),
    96       m_effect_cube_zrot(0.0f)
     96      m_effect_cube_zrot(0.0f),
     97      m_effect_kenBurns_image_ready(true),
     98      m_effect_kenBurns_initialized(false),
     99      m_effect_kenBurns_new_image_started(true)
    97100{
    98101    m_scaleMax = (gContext->GetNumSetting("GalleryScaleMax", 0) > 0);
    99102
     
    673676    m_effect_map.insert("slide (gl)",      "EffectSlide");
    674677    m_effect_map.insert("flutter (gl)",    "EffectFlutter");
    675678    m_effect_map.insert("cube (gl)",       "EffectCube");
     679    m_effect_map.insert("Ken Burns (gl)",  "EffectKenBurns");
    676680}
    677681
    678682void GLSingleView::RunEffect(const QString &effect)
     
    695699        EffectFlutter();
    696700    else if (effect == "EffectCube")
    697701        EffectCube();
     702    else if (effect == "EffectKenBurns")
     703        EffectKenBurns();
    698704    else //if (effect == "EffectNone")
    699705        EffectNone();
    700706}
     
    11781184    m_effect_current_frame++;
    11791185}
    11801186
     1187void GLSingleView::EffectKenBurns(void)
     1188{
     1189
     1190    float single_image_pct = 0.75;
     1191    float trans_pct = 1.0 - single_image_pct;
     1192    float scale_max, x_loc, y_loc;
     1193    float scale_factor = 0;
     1194
     1195    //initialize effect   
     1196    if (!m_effect_kenBurns_initialized)
     1197    {
     1198        m_effect_kenBurns_initialized = !m_effect_kenBurns_initialized;
     1199        m_effect_kenBurns_item = NULL;
     1200        // Need to load images in the background to keep effect smooth
     1201        m_effect_kenBurns_imageLoadThread = new KenBurnsImageLoader(this, m_itemList, m_texSize, m_screenSize);
     1202        //Since total image time is longer/different than effect time, create image timers
     1203        m_effect_kenBurns_image_time[m_texCur ? 0 : 1].restart();
     1204        // Pan image to a random location
     1205        m_effect_kenBurns_location_x[0] = (2.0 * rand() / (RAND_MAX + 1.0f)) - 1;
     1206        m_effect_kenBurns_location_y[0] = (2.0 * rand() / (RAND_MAX + 1.0f)) - 1;
     1207        // Since first two images are preloaded, harcode  them to zoom in
     1208        m_effect_kenBurns_projection[0] = 1;
     1209        m_effect_kenBurns_projection[1] = 1;
     1210        m_effect_kenBurns_image_timeout_inv = 1 / (m_effect_transition_timeout +
     1211                (m_effect_transition_timeout * trans_pct));
     1212    }
     1213
     1214    if (m_effect_frame_time.elapsed() >= m_effect_transition_timeout)
     1215    {
     1216        // Effect timed out, move new image to old image but don't load new image yet...
     1217        m_tex1First = !m_tex1First;
     1218        m_texCur      = (m_texCur) ? 0 : 1;
     1219        m_effect_current_frame  = 0;
     1220        m_effect_frame_time.restart();
     1221
     1222        if (m_effect_kenBurns_item) // Since first two images are preloaded dont randomly select sizefactor
     1223            // Randomly determine whether to zoom in or zoom out
     1224            m_effect_kenBurns_projection[m_texCur] = 1 + (int)((2.0f * rand() / (RAND_MAX + 1.0f)));
     1225
     1226        m_effect_kenBurns_image_ready = false;
     1227
     1228        // Find next image to be loaded
     1229        int oldpos = m_pos;
     1230
     1231        while (true)
     1232        {
     1233            m_pos = m_slideshow_sequence->next();
     1234            m_effect_kenBurns_item = m_itemList.at(m_pos);
     1235            if (m_effect_kenBurns_item)
     1236            {
     1237                // Skip movies
     1238                if (QFile::exists(m_effect_kenBurns_item->GetPath()) && !GalleryUtil::isMovie(m_effect_kenBurns_item->GetPath()))
     1239                {
     1240                    break;
     1241                }
     1242            }
     1243            if (m_pos == oldpos)
     1244            {
     1245                // No valid items!!!
     1246                close();
     1247            }
     1248        }
     1249        m_effect_kenBurns_imageLoadThread->Initialize(m_pos);
     1250        m_effect_kenBurns_imageLoadThread->start();
     1251    }
     1252
     1253    float t[2];
     1254    t[m_texCur] = m_effect_kenBurns_image_time[m_texCur].elapsed() * m_effect_kenBurns_image_timeout_inv;
     1255    t[m_texCur ? 0 : 1] = m_effect_kenBurns_image_time[m_texCur ? 0 : 1].elapsed() *
     1256    m_effect_kenBurns_image_timeout_inv;
     1257    float effect_pct = m_effect_frame_time.elapsed() *  m_effect_transition_timeout_inv;
     1258
     1259    // Load new image if its ready
     1260    if (effect_pct > single_image_pct && m_effect_kenBurns_image_ready)
     1261    {
     1262        if (!m_effect_kenBurns_new_image_started)
     1263        {                       
     1264            if (m_effect_kenBurns_item) //Do not create textures for first two images, since they are preloaded
     1265            {
     1266                m_texItem[!m_tex1First].SetItem(m_effect_kenBurns_item, m_effect_kenBurns_orig_image_size);
     1267                m_texItem[!m_tex1First].ScaleTo(m_screenSize, false);
     1268                m_texItem[!m_tex1First].Init(m_effect_kenBurns_image);
     1269                UpdateLCD(m_effect_kenBurns_item);
     1270            }
     1271
     1272            m_effect_kenBurns_location_x[m_texCur] = (2.0 * rand() / (RAND_MAX + 1.0f)) - 1;
     1273            m_effect_kenBurns_location_y[m_texCur] = (2.0 * rand() / (RAND_MAX + 1.0f)) - 1;
     1274            m_effect_kenBurns_image_time[m_texCur].restart();
     1275            m_effect_kenBurns_new_image_started = true;
     1276        }
     1277        if (m_effect_kenBurns_projection[m_texCur] == 1) // Zoom in image
     1278        {
     1279            // Start in center and pan out
     1280            x_loc = m_effect_kenBurns_location_x[m_texCur] * t[m_texCur];
     1281            y_loc = m_effect_kenBurns_location_y[m_texCur] * t[m_texCur];               
     1282            scale_max = FindMaxScale(x_loc,y_loc);
     1283            scale_factor =      1.0f + (scale_max * t[m_texCur]);
     1284        }
     1285        else // Zoom out image
     1286        {
     1287            // Start at random location and pan to center
     1288            x_loc = m_effect_kenBurns_location_x[m_texCur] -  m_effect_kenBurns_location_x[m_texCur] * t[m_texCur];
     1289            y_loc = m_effect_kenBurns_location_y[m_texCur] -  m_effect_kenBurns_location_y[m_texCur] * t[m_texCur];
     1290            scale_max = FindMaxScale(x_loc,y_loc);
     1291            scale_factor =      1.0f + scale_max -  (scale_max * t[m_texCur]);
     1292        }
     1293
     1294        glMatrixMode(GL_MODELVIEW);
     1295        glLoadIdentity();
     1296        glTranslatef(x_loc, y_loc, 0.0f);
     1297
     1298        m_texItem[m_texCur].MakeQuad((effect_pct-single_image_pct)*4, scale_factor);
     1299    }
     1300
     1301    //Load old picture
     1302    if (m_effect_kenBurns_projection[m_texCur ? 0 : 1] == 1)
     1303    {
     1304        x_loc = m_effect_kenBurns_location_x[m_texCur ? 0 : 1] * t[m_texCur ? 0 : 1];
     1305        y_loc = m_effect_kenBurns_location_y[m_texCur ? 0 : 1] * t[m_texCur ? 0 : 1];
     1306        scale_max = FindMaxScale(x_loc,y_loc);
     1307        scale_factor =  1.0f + (scale_max * t[m_texCur ? 0 : 1]);
     1308    }
     1309    else
     1310    {
     1311        x_loc = m_effect_kenBurns_location_x[m_texCur ? 0 : 1] -  m_effect_kenBurns_location_x[m_texCur ? 0 : 1] * t[m_texCur ? 0 : 1];
     1312        y_loc = m_effect_kenBurns_location_y[m_texCur ? 0 : 1] -  m_effect_kenBurns_location_y[m_texCur ? 0 : 1] * t[m_texCur ? 0 : 1];
     1313        scale_max = FindMaxScale(x_loc,y_loc);
     1314        scale_factor =  1.0f + scale_max -  (scale_max * t[m_texCur ? 0 : 1]);
     1315    }
     1316
     1317    glMatrixMode(GL_MODELVIEW);
     1318    glLoadIdentity();
     1319    glTranslatef(x_loc, y_loc, 0.0f);
     1320
     1321    if (effect_pct<= single_image_pct)
     1322    {
     1323        m_effect_kenBurns_new_image_started=false;
     1324        m_texItem[m_texCur ? 0 : 1].MakeQuad(1.0f, scale_factor); //
     1325    }
     1326    else // Fade out image
     1327    {
     1328        m_texItem[m_texCur ? 0 : 1].MakeQuad(1.0f - ((effect_pct-single_image_pct)*4), scale_factor);
     1329
     1330    }
     1331
     1332    m_effect_current_frame++;
     1333}
     1334
    11811335void GLSingleView::SlideTimeout(void)
    11821336{
    11831337    bool wasMovie = false, isMovie = false;
     
    12821436    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    12831437    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    12841438}
     1439
     1440void GLSingleView::LoadImage(QImage image, QSize origSize)
     1441{
     1442    m_effect_kenBurns_image = image;
     1443    m_effect_kenBurns_orig_image_size = origSize;
     1444}
     1445
     1446float GLSingleView::FindMaxScale(float x_loc, float y_loc)
     1447{
     1448    // Zoom big enough to keep the entire image on screen when we pan
     1449    if (abs(x_loc) > abs(y_loc))
     1450        return abs(x_loc) * 2;
     1451    else
     1452        return abs(y_loc) * 2;
     1453}
     1454
     1455KenBurnsImageLoader::KenBurnsImageLoader(GLSingleView *singleView, ThumbList &itemList, QSize texSize, QSize screenSize)
     1456{
     1457    m_singleView = singleView;
     1458    m_itemList = itemList;
     1459    m_texSize = texSize;
     1460    m_screenSize = screenSize;
     1461}
     1462
     1463void KenBurnsImageLoader::Initialize(int pos)
     1464{
     1465    m_pos = pos;
     1466}
     1467
     1468void KenBurnsImageLoader::run()
     1469{
     1470    ThumbItem *item = m_itemList.at(m_pos);
     1471    if (!item)
     1472    {
     1473        VERBOSE(VB_IMPORTANT, LOC_ERR + "No item at "<<m_pos);
     1474        return;
     1475    }
     1476    QImage image(item->GetPath());
     1477    if (image.isNull())
     1478        return;
     1479
     1480    m_singleView->LoadImage(QGLWidget::convertToGLFormat(image.smoothScale(m_texSize)), image.size());
     1481    m_singleView->Ready();
     1482
     1483}
  • mythgallery/glsingleview.h

     
    2727#include <qgl.h>
    2828#include <qmap.h>
    2929#include <qsize.h>
     30#include <QThread>
    3031
    3132// MythTV plugin headers
    3233#include <mythtv/util.h>
     
    4243class QTimer;
    4344
    4445class GLSingleView;
     46class KenBurnsImageLoader;
    4547
    4648class GLSDialog : public MythDialog
    4749{
     
    6769    ~GLSingleView();
    6870
    6971    void CleanUp(void);
     72    void Ready(){m_effect_kenBurns_image_ready = true;}
     73    void LoadImage(QImage image, QSize origSize);
     74   
    7075
    7176  protected:
    7277    void initializeGL(void);
     
    104109    void EffectSlide(void);
    105110    void EffectFlutter(void);
    106111    void EffectCube(void);
    107 
     112    void EffectKenBurns(void);
     113 
     114  private:
     115        float FindMaxScale(float x_loc, float y_loc);
     116   
    108117  private slots:
    109118    void SlideTimeout(void);
    110119
     
    135144    float         m_effect_cube_xrot;
    136145    float         m_effect_cube_yrot;
    137146    float         m_effect_cube_zrot;
     147    float         m_effect_kenBurns_location_x[2];
     148    float         m_effect_kenBurns_location_y[2];
     149    int           m_effect_kenBurns_projection[2];
     150    MythTimer     m_effect_kenBurns_image_time[2];
     151    float         m_effect_kenBurns_image_timeout_inv;
     152    KenBurnsImageLoader *m_effect_kenBurns_imageLoadThread;
     153    bool          m_effect_kenBurns_image_ready;
     154    QImage        m_effect_kenBurns_image;
     155    QSize         m_effect_kenBurns_orig_image_size;
     156    ThumbItem     *m_effect_kenBurns_item;
     157    bool          m_effect_kenBurns_initialized;
     158    bool          m_effect_kenBurns_new_image_started;
     159   
    138160};
    139161
     162class KenBurnsImageLoader : public QThread
     163{
     164public:
     165    KenBurnsImageLoader(GLSingleView *singleView, ThumbList &itemList, QSize m_texSize, QSize m_screenSize);
     166    void Initialize(int pos);
     167    void run();
     168private:
     169        GLSingleView *m_singleView;
     170    ThumbList     m_itemList;
     171    int           m_pos;
     172    bool          m_tex1First;
     173    QSize         m_screenSize;
     174    QSize         m_texSize;
     175
     176};
     177
    140178#endif // USING_OPENGL
    141179#endif // GLSINGLEVIEW_H
  • mythgallery/imageview.cpp

     
    136136{
    137137    QMap<QString,QString> tmpMap = m_effect_map;
    138138    tmpMap.remove("none");
     139    tmpMap.remove("Ken Burns (gl)");
    139140    QStringList t = tmpMap.keys();
    140141    int i = (int) ( (float)(t.count()) * rand() / (RAND_MAX + 1.0f) );
    141142    return tmpMap[t[i]];
  • mythgallery/gallerysettings.cpp

     
    105105    gc->addSelection("flutter (gl)");
    106106    gc->addSelection("cube (gl)");
    107107    gc->addSelection("random (gl)");
     108    gc->addSelection("Ken Burns (gl)");
    108109    gc->setHelpText(QObject::tr("This is the type of OpenGL transition used "
    109110                    "between pictures in slideshow mode."));
    110111    return gc;
     
    113114static HostSpinBox *SlideshowOpenGLTransitionLength()
    114115{
    115116    HostSpinBox *gc = new HostSpinBox(
    116         "SlideshowOpenGLTransitionLength", 500, 10000, 500);
     117        "SlideshowOpenGLTransitionLength", 500, 30000, 500);
    117118    gc->setLabel(QObject::tr("Duration of OpenGL Transition (milliseconds)"));
    118119    gc->setValue(2000);
    119120    return gc;
     
    159160
    160161static HostSpinBox *SlideshowDelay()
    161162{
    162     HostSpinBox *gc = new HostSpinBox("SlideshowDelay", 1, 600, 1);
     163    HostSpinBox *gc = new HostSpinBox("SlideshowDelay", 0, 600, 1);
    163164    gc->setLabel(QObject::tr("Slideshow Delay"));
    164165    gc->setValue(5);
    165166    gc->setHelpText(QObject::tr("This is the number of seconds to display each "