OSDN Git Service

Moved functions from lang.h to lang.c for easy includion in Controller.mm
[handbrake-jp/handbrake-jp-git.git] / macosx / PictureGLView.mm
index 79103f6..611fb3a 100644 (file)
@@ -1,69 +1,40 @@
-#include <OpenGL/gl.h>
-
-#include "PictureGLView.h"
+/* $Id: PictureGLView.mm,v 1.18 2005/08/01 15:10:44 titer Exp $
 
-@implementation HBPictureGLView
+   This file is part of the HandBrake source code.
+   Homepage: <http://handbrake.m0k.org/>.
+   It may be used under the terms of the GNU General Public License. */
 
-- (void) SetManager: (HBManager*) manager
-{
-    fManager = manager;
-}
+#include <OpenGL/OpenGL.h>
+#include <OpenGL/gl.h>
+#include <OpenGL/glext.h>
+#include <math.h>
 
-- (void) SetTitle: (HBTitle*) title
-{
-    fTitle = title;
-    /* This is needed as the view's size may have changed */
-    [self clearGLContext];
-    [self openGLContext];
-}
+#include "PictureGLView.h"
 
-- (void) ShowPicture: (int) index
+static int GetAlignedSize( int size )
 {
-    /* Get the picture */
-    uint8_t * tmp = fManager->GetPreview( fTitle, index );
-
-    /* Make it be upside-down */
-    if( fPicture ) free( fPicture );
-    fPicture = (uint8_t*) malloc( 4 * ( fTitle->fOutWidthMax + 2 ) *
-                                  ( fTitle->fOutHeightMax + 2 ) );
-    for( uint32_t i = 0; i < fTitle->fOutHeightMax + 2; i++ )
+    int result = 1;
+    while( result < size )
     {
-        memcpy( fPicture + 4 * ( fTitle->fOutWidthMax + 2 ) * i,
-                tmp + 4 * ( fTitle->fOutWidthMax + 2 ) *
-                    ( fTitle->fOutHeightMax + 1 - i ),
-                4 * ( fTitle->fOutWidthMax + 2 ) );
-    }
-    free( tmp );
-
-    /* Grrr - should find a way to give ARGB to OpenGL */
-    uint8_t r, g, b, a;
-    for( uint32_t i = 0; i < fTitle->fOutHeightMax + 2; i++ )
-    {
-        for( uint32_t j = 0; j < fTitle->fOutWidthMax + 2; j++ )
-        {
-            a = fPicture[4*(i*(fTitle->fOutWidthMax+2)+j)];
-            r = fPicture[4*(i*(fTitle->fOutWidthMax+2)+j)+1];
-            g = fPicture[4*(i*(fTitle->fOutWidthMax+2)+j)+2];
-            b = fPicture[4*(i*(fTitle->fOutWidthMax+2)+j)+3];
-
-            fPicture[4*(i*(fTitle->fOutWidthMax+2)+j)]   = r;
-            fPicture[4*(i*(fTitle->fOutWidthMax+2)+j)+1] = g;
-            fPicture[4*(i*(fTitle->fOutWidthMax+2)+j)+2] = b;
-            fPicture[4*(i*(fTitle->fOutWidthMax+2)+j)+3] = a;
-        }
+        result *= 2;
     }
-
-    [self setNeedsDisplay: YES];
+    return result;
 }
 
-/* Override NSView's initWithFrame: to specify our pixel format */
+@implementation HBPictureGLView
+
 - (id) initWithFrame: (NSRect) frame
 {
-    fManager = NULL;
-    fTitle   = NULL;
-    fPicture = NULL;
+    fHasQE  = CGDisplayUsesOpenGLAcceleration( kCGDirectMainDisplay );
+    fTarget = fHasQE ? GL_TEXTURE_RECTANGLE_EXT : GL_TEXTURE_2D;
+
+    fBuffers[0] = NULL;
+    fBuffers[1] = NULL;
+    fWidth      = 0;
+    fHeight     = 0;
 
+    fLastEffect = -1;
+    
     GLuint attribs[] =
     {
         NSOpenGLPFANoRecovery,
     NSOpenGLPixelFormat * fmt = [[NSOpenGLPixelFormat alloc]
         initWithAttributes: (NSOpenGLPixelFormatAttribute*) attribs];
 
-    if( !fmt )
+    self = [super initWithFrame:frame pixelFormat: [fmt autorelease]];
+
+    if( !self )
     {
-        fprintf( stderr, "Sarass\n" );
+        return NULL;
     }
 
-    return self = [super initWithFrame:frame pixelFormat:
-                      [fmt autorelease]];
+    [[self openGLContext] makeCurrentContext];
+    [self reshape];
+
+    glGenTextures( 2, fTextures );
+
+    return self;
+}
+
+- (void) reshape
+{
+    NSRect bounds;
+    [[self openGLContext] update];
+    [[self openGLContext] makeCurrentContext];
+    bounds = [self bounds];
+    glViewport( 0, 0, (int) bounds.size.width,
+                (int) bounds.size.height );
 }
 
-/* Override the view's drawRect: to draw our GL content */
 - (void) drawRect: (NSRect) rect
 {
-    glViewport( 0, 0, (GLsizei) rect.size.width,
-                (GLsizei) rect.size.height );
+    [[self openGLContext] makeCurrentContext];
 
-    /* Black background */
-    glClearColor( 0, 0, 0, 0 );
-    glClear( GL_COLOR_BUFFER_BIT );
+    glDisable( GL_DEPTH_TEST );
+    glDisable( GL_CULL_FACE );
+    glDisable( GL_BLEND );
 
-    /* Show it */
-    if( fPicture )
+    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+    if( fBuffers[0] )
     {
-        glDrawPixels( fTitle->fOutWidthMax + 2,
-                      fTitle->fOutHeightMax + 2, GL_RGBA,
-                      GL_UNSIGNED_BYTE, fPicture );
-    }
+        glMatrixMode( GL_PROJECTION );
+        glLoadIdentity();
+        glMatrixMode( GL_MODELVIEW );
+        glLoadIdentity();
 
+        glEnable( fTarget );
+        glBindTexture( fTarget, fTextures[0] );
+        glTexImage2D( fTarget, 0, GL_RGBA, fTexWidth, fTexHeight, 0,
+                      GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, fBuffers[0] );
+        glTexParameteri( fTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+        glTexParameteri( fTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+
+        glBegin( GL_QUADS );
+        glTexCoord2f( 0.0    , 0.0     ); glVertex2f( -1.0,  1.0 );
+        glTexCoord2f( 0.0    , fCoordY ); glVertex2f( -1.0, -1.0 );
+        glTexCoord2f( fCoordX, fCoordY ); glVertex2f(  1.0, -1.0 );
+        glTexCoord2f( fCoordX, 0.0     ); glVertex2f(  1.0,  1.0 );
+        glEnd();
+    }
     [[self openGLContext] flushBuffer];
 }
 
+#define FRUSTUM_NEAR   2.5
+#define FRUSTUM_FAR    20.0
+
+- (void) drawCube: (int) anim
+{
+    uint64_t date;
+    float w, rotation, translation;
+    
+    w = ( anim & HB_ANIMATE_BACKWARD ) ? 1.0 : -1.0;
+
+    glEnable( GL_DEPTH_TEST );
+    glEnable( GL_CULL_FACE );
+    glDisable( GL_BLEND );
+
+    for( rotation = 0.0; w * rotation < 90.0;
+         rotation += w * 90 * 1000 / fAnimDuration / fFrameRate )
+    {
+        date = hb_get_date();
+        translation = - FRUSTUM_NEAR - cos( rotation * M_PI / 180 ) *
+            ( 1 + w * tan( rotation * M_PI / 180 ) );
+
+        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+        glMatrixMode( GL_PROJECTION );
+        glLoadIdentity();
+        glFrustum( -1.0, 1.0, -1.0, 1.0, FRUSTUM_NEAR, FRUSTUM_FAR );
+        glMatrixMode( GL_MODELVIEW );
+        glLoadIdentity();
+        glTranslatef( 0.0, 0.0, translation );
+        glRotatef( rotation, 0.0, 1.0, 0.0 );
+     
+        glBindTexture( fTarget, fTextures[0] );
+        glBegin( GL_QUADS );
+        glTexCoord2f( 0.0    , 0.0 );     glVertex3f( -1.0,  1.0, 1.0 );
+        glTexCoord2f( 0.0    , fCoordY ); glVertex3f( -1.0, -1.0, 1.0 );
+        glTexCoord2f( fCoordX, fCoordY ); glVertex3f(  1.0, -1.0, 1.0 );
+        glTexCoord2f( fCoordX, 0.0 );     glVertex3f(  1.0,  1.0, 1.0 );
+        glEnd();
+     
+        glBindTexture( fTarget, fTextures[1] );
+        glBegin( GL_QUADS );
+        if( anim & HB_ANIMATE_FORWARD )
+        {
+            glTexCoord2f( 0.0,    0.0 );     glVertex3f( 1.0,  1.0,  1.0 );
+            glTexCoord2f( 0.0,    fCoordY ); glVertex3f( 1.0, -1.0,  1.0 );
+            glTexCoord2f( fCoordX, fCoordY ); glVertex3f( 1.0, -1.0, -1.0 );
+            glTexCoord2f( fCoordX, 0.0 );     glVertex3f( 1.0,  1.0, -1.0 );
+        }
+        else
+        {
+            glTexCoord2f( 0.0,    0.0 );     glVertex3f( -1.0,  1.0, -1.0 );
+            glTexCoord2f( 0.0,    fCoordY ); glVertex3f( -1.0, -1.0, -1.0 );
+            glTexCoord2f( fCoordX, fCoordY ); glVertex3f( -1.0, -1.0,  1.0 );
+            glTexCoord2f( fCoordX, 0.0 );     glVertex3f( -1.0,  1.0,  1.0 );
+        }
+        glEnd();
+     
+        [[self openGLContext] flushBuffer];
+
+        hb_snooze( 1000 / fFrameRate - ( hb_get_date() - date ) );
+    }
+
+}
+
+- (void) drawSwap: (int) anim
+{
+    uint64_t date;
+    float w, rotation, x, z;
+    
+    w = ( anim & HB_ANIMATE_BACKWARD ) ? 1.0 : -1.0;
+
+    glEnable( GL_DEPTH_TEST );
+    glEnable( GL_CULL_FACE );
+    glDisable( GL_BLEND );
+
+    glMatrixMode( GL_PROJECTION );
+    glLoadIdentity();
+    glFrustum( -1.0, 1.0, -1.0, 1.0, FRUSTUM_NEAR, FRUSTUM_FAR );
+    glMatrixMode( GL_MODELVIEW );
+    glLoadIdentity();
+    glTranslatef( 0.0, 0.0, - FRUSTUM_NEAR - 1.0 );
+
+    for( rotation = 0.0; w * rotation < 180.0;
+         rotation += w * 180 * 1000 / fAnimDuration / fFrameRate )
+    {
+        date = hb_get_date();
+
+        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+        x = 1.1 * sin( rotation * M_PI / 180 );
+        z = cos( rotation * M_PI / 180 );
+
+        glBindTexture( fTarget, fTextures[0] );
+        glBegin( GL_QUADS );
+        glTexCoord2f( 0.0,    0.0 );     glVertex3f( -1.0 + x,  1.0, z );
+        glTexCoord2f( 0.0,    fCoordY ); glVertex3f( -1.0 + x, -1.0, z );
+        glTexCoord2f( fCoordX, fCoordY ); glVertex3f(  1.0 + x, -1.0, z );
+        glTexCoord2f( fCoordX, 0.0 );     glVertex3f(  1.0 + x,  1.0, z );
+        glEnd();
+     
+        glBindTexture( fTarget, fTextures[1] );
+        glBegin( GL_QUADS );
+        glTexCoord2f( 0.0,    0.0 );     glVertex3f( -1.0 - x,  1.0, - z );
+        glTexCoord2f( 0.0,    fCoordY ); glVertex3f( -1.0 - x, -1.0, - z );
+        glTexCoord2f( fCoordX, fCoordY ); glVertex3f(  1.0 - x, -1.0, - z );
+        glTexCoord2f( fCoordX, 0.0 );     glVertex3f(  1.0 - x,  1.0, - z );
+        glEnd();
+     
+        [[self openGLContext] flushBuffer];
+
+        hb_snooze( 1000 / fFrameRate - ( hb_get_date() - date ) );
+    }
+}
+
+- (void) drawFade
+{
+    uint64_t date;
+    float alpha;
+
+    glDisable( GL_DEPTH_TEST );
+    glDisable( GL_CULL_FACE );
+    glEnable( GL_BLEND );
+
+    glMatrixMode( GL_PROJECTION );
+    glLoadIdentity();
+    glMatrixMode( GL_MODELVIEW );
+    glLoadIdentity();
+
+    for( alpha = 0.0; alpha < 1.0;
+         alpha += 1000.0 / fAnimDuration / fFrameRate )
+    {
+        date = hb_get_date();
+
+        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+        glColor4f( 1.0, 1.0, 1.0, 1.0 - alpha );
+        glBlendFunc( GL_SRC_ALPHA, GL_ONE );
+
+        glBindTexture( fTarget, fTextures[0] );
+        glBegin( GL_QUADS );
+        glTexCoord2f( 0.0,    0.0 );     glVertex2f( -1.0,  1.0 );
+        glTexCoord2f( 0.0,    fCoordY ); glVertex2f( -1.0, -1.0 );
+        glTexCoord2f( fCoordX, fCoordY ); glVertex2f(  1.0, -1.0 );
+        glTexCoord2f( fCoordX, 0.0 );     glVertex2f(  1.0,  1.0 );
+        glEnd();
+
+        glColor4f( 1.0, 1.0, 1.0, alpha );
+        glBlendFunc( GL_SRC_ALPHA, GL_ONE );
+
+        glBindTexture( fTarget, fTextures[1] );
+        glBegin( GL_QUADS );
+        glTexCoord2f( 0.0,    0.0 );     glVertex2f( -1.0,  1.0 );
+        glTexCoord2f( 0.0,    fCoordY ); glVertex2f( -1.0, -1.0 );
+        glTexCoord2f( fCoordX, fCoordY ); glVertex2f(  1.0, -1.0 );
+        glTexCoord2f( fCoordX, 0.0 );     glVertex2f(  1.0,  1.0 );
+        glEnd();
+
+        [[self openGLContext] flushBuffer];
+
+        hb_snooze( 1000 / fFrameRate - ( hb_get_date() - date ) );
+    }
+}
+
+- (void) drawSlide: (int) anim
+{
+    uint64_t date;
+    float foo, w;
+    int left, right;
+    if( anim & HB_ANIMATE_FORWARD )
+    {
+        left  = 0;
+        right = 1;
+        w     = 1.0;
+    }
+    else
+    {
+        left  = 1;
+        right = 0;
+        w     = -1.0;
+    }
+
+    glDisable( GL_DEPTH_TEST );
+    glDisable( GL_CULL_FACE );
+    glDisable( GL_BLEND );
+
+    glMatrixMode( GL_PROJECTION );
+    glLoadIdentity();
+    glMatrixMode( GL_MODELVIEW );
+    glLoadIdentity();
+
+    for( foo = w; foo >= -1.0 && foo <= 1.0;
+         foo -= w * 2000.0 / fAnimDuration / fFrameRate )
+    {
+        date = hb_get_date();
+
+        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+        glBindTexture( fTarget, fTextures[left] );
+        glBegin( GL_QUADS );
+        glTexCoord2f( 0.0,    0.0 );     glVertex2f( foo - 2.0,  1.0 );
+        glTexCoord2f( 0.0,    fCoordY ); glVertex2f( foo - 2.0, -1.0 );
+        glTexCoord2f( fCoordX, fCoordY ); glVertex2f( foo,       -1.0 );
+        glTexCoord2f( fCoordX, 0.0 );     glVertex2f( foo,        1.0 );
+        glEnd();
+
+        glBindTexture( fTarget, fTextures[right] );
+        glBegin( GL_QUADS );
+        glTexCoord2f( 0.0,    0.0 );     glVertex2f( foo,        1.0 );
+        glTexCoord2f( 0.0,    fCoordY ); glVertex2f( foo,       -1.0 );
+        glTexCoord2f( fCoordX, fCoordY ); glVertex2f( foo + 2.0, -1.0 );
+        glTexCoord2f( fCoordX, 0.0 );     glVertex2f( foo + 2.0,  1.0 );
+        glEnd();
+
+        [[self openGLContext] flushBuffer];
+
+        hb_snooze( 1000 / fFrameRate - ( hb_get_date() - date ) );
+    }
+}
+
+#undef FRUSTUM_NEAR
+#undef FRUSTUM_FAR
+
+- (void) drawAnimation: (int) anim
+{
+    glEnable( fTarget );
+
+    glBindTexture( fTarget, fTextures[0] );
+    glTexImage2D( fTarget, 0, GL_RGBA, fTexWidth, fTexHeight, 0,
+                  GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, fBuffers[1] );
+    glTexParameteri( fTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+    glTexParameteri( fTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+
+    glBindTexture( fTarget, fTextures[1] );
+    glTexImage2D( fTarget, 0, GL_RGBA, fTexWidth, fTexHeight, 0,
+                  GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, fBuffers[0] );
+    glTexParameteri( fTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+    glTexParameteri( fTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+
+    /* Draw a random animation, just making sure we don't use the same
+       effect two times in a row */
+    int effect;
+    do
+    {
+        effect = hb_get_date() % 4;
+    }
+    while( effect == fLastEffect );
+
+    fAnimDuration = ( anim & HB_ANIMATE_SLOW ) ? 3000 : 600;
+    fFrameRate    = 60.0;
+    
+    switch( effect )
+    {
+        case 0:
+            [self drawCube: anim];
+            break;
+        case 1:
+            [self drawSwap: anim];
+            break;
+        case 2:
+            [self drawFade];
+            break;
+        case 3:
+            [self drawSlide: anim];
+            break;
+    }
+
+    fLastEffect = effect;
+}
+
+- (void) Display: (int) anim buffer1: (uint8_t *) buffer1
+    buffer2: (uint8_t *) buffer2 width: (int) width height: (int) height
+{
+    [[self openGLContext] makeCurrentContext];
+
+    if( width != fWidth || height != fHeight )
+    {
+        fWidth  = width;
+        fHeight = height;
+        if( fHasQE )
+        {
+            fTexWidth  = fWidth;
+            fTexHeight = fHeight;
+            fCoordX    = (float) fWidth;
+            fCoordY    = (float) fHeight;
+        }
+        else
+        {
+            fTexWidth  = GetAlignedSize( fWidth );
+            fTexHeight = GetAlignedSize( fHeight );
+            fCoordX    = (float) fWidth  / (float) fTexWidth;
+            fCoordY    = (float) fHeight / (float) fTexHeight;
+        }
+        [self clearGLContext];
+        [self openGLContext];
+        [self reshape];
+    }
+
+    fBuffers[0] = buffer1;
+    fBuffers[1] = buffer2;
+
+    /* Swap buffers only during the vertical retrace of the monitor.
+       http://developer.apple.com/documentation/GraphicsImaging/
+       Conceptual/OpenGL/chap5/chapter_5_section_44.html */
+    long params[] = { 1 };
+    CGLSetParameter( CGLGetCurrentContext(), kCGLCPSwapInterval,
+                     params );
+
+    if( !( anim & HB_ANIMATE_NONE ) )
+    {
+        [self drawAnimation: anim];
+    }
+    
+    [self drawRect: [self bounds]];
+}
+
 @end