From 7ffc3d40803e8624a47a45a779ff7899ae6b84f9 Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Sun, 24 Jan 2010 19:05:20 +0000 Subject: [PATCH] Move more of the purely OpenGL-related code into VideoOutGL from VideoDisplay and simplify the calculation of the texture grid positions slightly. Originally committed to SVN as r4037. --- aegisub/src/gl_text.cpp | 1 + aegisub/src/video_display.cpp | 33 +-------- aegisub/src/video_display.h | 10 ++- aegisub/src/video_out_gl.cpp | 126 +++++++++++++++++++++------------- aegisub/src/video_out_gl.h | 9 +++ 5 files changed, 93 insertions(+), 86 deletions(-) diff --git a/aegisub/src/gl_text.cpp b/aegisub/src/gl_text.cpp index 81d096315..135b2d0df 100644 --- a/aegisub/src/gl_text.cpp +++ b/aegisub/src/gl_text.cpp @@ -145,6 +145,7 @@ void OpenGLText::DoPrint(wxString text,int x,int y) { DrawString(text,x,y); // Disable blend + glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); } diff --git a/aegisub/src/video_display.cpp b/aegisub/src/video_display.cpp index 859f589a0..1fe10cdc4 100644 --- a/aegisub/src/video_display.cpp +++ b/aegisub/src/video_display.cpp @@ -240,7 +240,7 @@ void VideoDisplay::SetFrameRange(int from, int to) { /// @brief Render the currently visible frame void VideoDisplay::Render() try { if (!IsShownOnScreen()) return; - if (!wxIsMainThread()) throw _T("Error: trying to render from non-primary thread"); + wxASSERT(wxIsMainThread()); VideoContext *context = VideoContext::Get(); wxASSERT(context); @@ -260,14 +260,6 @@ void VideoDisplay::Render() try { wxASSERT(pw > 0); wxASSERT(ph > 0); - // Clear frame buffer - glClearColor(0,0,0,0); - if (glGetError()) throw _T("Error setting glClearColor()."); - glClearStencil(0); - if (glGetError()) throw _T("Error setting glClearStencil()."); - glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - if (glGetError()) throw _T("Error calling glClear()."); - // Freesized transform dx1 = 0; dy1 = 0; @@ -293,21 +285,7 @@ void VideoDisplay::Render() try { } } - // Set viewport - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glViewport(dx1,dy1,dx2,dy2); - if (glGetError()) throw _T("Error setting GL viewport."); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0.0f,sw,sh,0.0f,-1000.0f,1000.0f); - glMatrixMode(GL_MODELVIEW); - if (glGetError()) throw _T("Error setting up matrices (wtf?)."); - glShadeModel(GL_FLAT); - - glDisable(GL_BLEND); - if (glGetError()) throw _T("Error disabling blending."); - + videoOut->SetViewport(dx1, dy1, dx2, dy2); videoOut->Render(sw, sh); DrawTVEffects(); @@ -325,13 +303,6 @@ catch (const VideoOutException &err) { err.GetMessage().c_str()); VideoContext::Get()->Reset(); } -catch (const wxChar *err) { - wxLogError( - _T("An error occurred trying to render the video frame to screen.\n") - _T("Error message reported: %s"), - err); - VideoContext::Get()->Reset(); -} catch (...) { wxLogError( _T("An error occurred trying to render the video frame to screen.\n") diff --git a/aegisub/src/video_display.h b/aegisub/src/video_display.h index 9563a07fd..c24f018b0 100644 --- a/aegisub/src/video_display.h +++ b/aegisub/src/video_display.h @@ -70,17 +70,15 @@ private: /// The height of the display int h; - /// The x-coordinate of the top left of the area containing video. + /// The x-coordinate of the bottom left of the area containing video. /// Always zero unless the display is detatched and is wider than the video. int dx1; - /// The x-coordinate of the bottom right of the area containing video. - /// Always equal to the width of the video unless the display is detatched and is wider than the video. + /// The width of the screen area containing video int dx2; - /// The y-coordinate of the top left of the area containing video. + /// The y-coordinate of the bottom left of the area containing video. /// Always zero unless the display is detatched and is taller than the video. int dy1; - /// The y-coordinate of the bottom of the area containing video. - /// Always equal to the height of the video unless the display is detatched and is taller than the video. + /// The height of the screen area containing video int dy2; /// The x position of the mouse diff --git a/aegisub/src/video_out_gl.cpp b/aegisub/src/video_out_gl.cpp index e979a3af0..db3ce0ce8 100644 --- a/aegisub/src/video_out_gl.cpp +++ b/aegisub/src/video_out_gl.cpp @@ -70,18 +70,30 @@ struct VideoOutGL::TextureInfo { int sourceH; int sourceW; - int textureH; - int textureW; - - float destH; - float destW; - float destX; - float destY; + float destX1; + float destY1; + float destX2; + float destY2; float texTop; float texBottom; float texLeft; float texRight; + + TextureInfo() + : textureID(0) + , dataOffset(0) + , sourceH(0) + , sourceW(0) + , destX1(0) + , destY1(0) + , destX2(0) + , destY2(0) + , texTop(0) + , texBottom(1.0f) + , texLeft(0) + , texRight(1.0f) + { } }; /// @brief Test if a texture can be created @@ -152,6 +164,10 @@ void VideoOutGL::DetectOpenGLCapabilities() { void VideoOutGL::InitTextures(int width, int height, GLenum format, int bpp, bool flipped) { // Do nothing if the frame size and format are unchanged if (width == frameWidth && height == frameHeight && format == frameFormat && flipped == frameFlipped) return; + frameWidth = width; + frameHeight = height; + frameFormat = format; + frameFlipped = flipped; wxLogDebug("VideoOutGL::InitTextures: Video size: %dx%d\n", width, height); DetectOpenGLCapabilities(); @@ -172,10 +188,10 @@ void VideoOutGL::InitTextures(int width, int height, GLenum format, int bpp, boo // Calculate the position information for each texture int sourceY = 0; - float destY = 0.0f; + float destY = -1.0f; for (int i = 0; i < textureRows; i++) { int sourceX = 0; - float destX = 0.0f; + float destX = -1.0f; int sourceH = maxTextureSize; int textureH = maxTextureSize; @@ -184,13 +200,15 @@ void VideoOutGL::InitTextures(int width, int height, GLenum format, int bpp, boo sourceH = height % maxTextureSize; textureH = SmallestPowerOf2(sourceH); } + for (int j = 0; j < textureCols; j++) { TextureInfo& ti = textureList[i * textureCols + j]; // Copy the current position information into the struct - ti.destX = destX; - ti.destY = destY; + ti.destX1 = destX; + ti.destY1 = destY; ti.sourceH = sourceH; + ti.textureID = textureIdList[i * textureCols + j]; ti.sourceW = maxTextureSize; int textureW = maxTextureSize; @@ -204,54 +222,49 @@ void VideoOutGL::InitTextures(int width, int height, GLenum format, int bpp, boo int h = textureH; if (!supportsRectangularTextures) w = h = MAX(w, h); - if (supportsGlClampToEdge) { - ti.texLeft = 0.0f; - ti.texTop = 0.0f; - } - else { + CreateTexture(w, h, ti, format); + + if (!supportsGlClampToEdge) { // Stretch the texture a half pixel in each direction to eliminate the border ti.texLeft = 1.0f / (2 * w); ti.texTop = 1.0f / (2 * h); } - ti.destW = float(w) / width; - ti.destH = float(h) / height; - - ti.textureID = textureIdList[i * textureCols + j]; - ti.dataOffset = sourceY * width * bpp + sourceX * bpp; + ti.destX2 = ti.destX1 + w * 2.0f / width; + ti.destY2 = ti.destY1 + h * 2.0f / height; ti.texRight = 1.0f - ti.texLeft; - ti.texBottom = 1.0f - ti.texTop; if (flipped) { + ti.texBottom = 1.0f - ti.texTop; + ti.dataOffset = sourceY * width * bpp + sourceX * bpp; + } + else { ti.texBottom = ti.texTop - float(h - ti.sourceH) / h; ti.texTop = 1.0f - ti.texTop - float(h - ti.sourceH) / h; ti.dataOffset = (height - sourceY - ti.sourceH) * width * bpp + sourceX * bpp; } - // Actually create the texture and set the scaling mode - CHECK_INIT_ERROR(glBindTexture(GL_TEXTURE_2D, ti.textureID)); - CHECK_INIT_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, w, h, 0, format, GL_UNSIGNED_BYTE, NULL)); - wxLogDebug("VideoOutGL::InitTextures: Using texture size: %dx%d\n", w, h); - CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); - CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); - - GLint mode = supportsGlClampToEdge ? GL_CLAMP_TO_EDGE : GL_CLAMP; - CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mode)); - CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mode)); - - destX += ti.destW; + destX = ti.destX2; sourceX += ti.sourceW; } - destY += float(sourceH) / height; + destY += sourceH * 2.0f / height; sourceY += sourceH; } - - // Store the information needed to know when the grid must be recreated - frameWidth = width; - frameHeight = height; - frameFormat = format; } + +void VideoOutGL::CreateTexture(int w, int h, const TextureInfo& ti, GLenum format) { + CHECK_INIT_ERROR(glBindTexture(GL_TEXTURE_2D, ti.textureID)); + CHECK_INIT_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, w, h, 0, format, GL_UNSIGNED_BYTE, NULL)); + wxLogDebug("VideoOutGL::InitTextures: Using texture size: %dx%d\n", w, h); + CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + + GLint mode = supportsGlClampToEdge ? GL_CLAMP_TO_EDGE : GL_CLAMP; + CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, mode)); + CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, mode)); +} + void VideoOutGL::UploadFrameData(const AegiVideoFrame& frame) { if (frame.h == 0 || frame.w == 0) return; @@ -271,30 +284,45 @@ void VideoOutGL::UploadFrameData(const AegiVideoFrame& frame) { CHECK_ERROR(glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)); } +void VideoOutGL::SetViewport(int x, int y, int width, int height) { + CHECK_ERROR(glViewport(x, y, width, height)); +} void VideoOutGL::Render(int sw, int sh) { + // Clear the frame buffer + CHECK_ERROR(glClearColor(0,0,0,0)); + CHECK_ERROR(glClearStencil(0)); + CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)); + + + CHECK_ERROR(glShadeModel(GL_FLAT)); + CHECK_ERROR(glDisable(GL_BLEND)); + + CHECK_ERROR(glMatrixMode(GL_PROJECTION)); + CHECK_ERROR(glLoadIdentity()); + + // Render the current frame CHECK_ERROR(glEnable(GL_TEXTURE_2D)); for (unsigned i = 0; i < textureList.size(); i++) { TextureInfo& ti = textureList[i]; - float destX = ti.destX * sw; - float destW = ti.destW * sw; - float destY = ti.destY * sh; - float destH = ti.destH * sh; - CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, ti.textureID)); CHECK_ERROR(glColor4f(1.0f, 1.0f, 1.0f, 1.0f)); glBegin(GL_QUADS); - glTexCoord2f(ti.texLeft, ti.texTop); glVertex2f(destX, destY); - glTexCoord2f(ti.texRight, ti.texTop); glVertex2f(destX + destW, destY); - glTexCoord2f(ti.texRight, ti.texBottom); glVertex2f(destX + destW, destY + destH); - glTexCoord2f(ti.texLeft, ti.texBottom); glVertex2f(destX, destY + destH); + glTexCoord2f(ti.texLeft, ti.texTop); glVertex2f(ti.destX1, ti.destY1); + glTexCoord2f(ti.texRight, ti.texTop); glVertex2f(ti.destX2, ti.destY1); + glTexCoord2f(ti.texRight, ti.texBottom); glVertex2f(ti.destX2, ti.destY2); + glTexCoord2f(ti.texLeft, ti.texBottom); glVertex2f(ti.destX1, ti.destY2); glEnd(); if (GLenum err = glGetError()) throw VideoOutRenderException(L"GL_QUADS", err); } CHECK_ERROR(glDisable(GL_TEXTURE_2D)); + + CHECK_ERROR(glOrtho(0.0f, sw, sh, 0.0f, -1000.0f, 1000.0f)); + CHECK_ERROR(glMatrixMode(GL_MODELVIEW)); + CHECK_ERROR(glLoadIdentity()); } VideoOutGL::~VideoOutGL() { diff --git a/aegisub/src/video_out_gl.h b/aegisub/src/video_out_gl.h index ef3cf8bd5..625f70caf 100644 --- a/aegisub/src/video_out_gl.h +++ b/aegisub/src/video_out_gl.h @@ -78,13 +78,22 @@ private: void DetectOpenGLCapabilities(); void InitTextures(int width, int height, GLenum format, int bpp, bool flipped); + void CreateTexture(int w, int h, const TextureInfo& ti, GLenum format); VideoOutGL(const VideoOutGL &); VideoOutGL& operator=(const VideoOutGL&); public: + /// @brief Set the viewport + /// @param x Bottom left x coordinate + /// @param y Bottom left y coordinate + /// @param width Width in pixels of viewport + /// @param height Height in pixels of viewport + void SetViewport(int x, int y, int width, int height); + /// @brief Set the frame to be displayed when Render() is called /// @param frame The frame to be displayed void UploadFrameData(const AegiVideoFrame& frame); + /// @brief Render a frame /// @param sw The current script width /// @param sh The current script height