diff --git a/aegisub/src/video_display.cpp b/aegisub/src/video_display.cpp index 3ea91506b..a0ed718ce 100644 --- a/aegisub/src/video_display.cpp +++ b/aegisub/src/video_display.cpp @@ -152,6 +152,7 @@ void VideoDisplay::ShowCursor(bool show) { } void VideoDisplay::SetFrame(int frameNumber) { + VideoContext *context = VideoContext::Get(); ControlSlider->SetValue(frameNumber); // Get time for frame @@ -163,7 +164,7 @@ void VideoDisplay::SetFrame(int frameNumber) { // Set the text box for frame number and time PositionDisplay->SetValue(wxString::Format(_T("%01i:%02i:%02i.%03i - %i"), h, m, s, ms, frameNumber)); - if (VideoContext::Get()->GetKeyFrames().Index(frameNumber) != wxNOT_FOUND) { + if (context->GetKeyFrames().Index(frameNumber) != wxNOT_FOUND) { // Set the background color to indicate this is a keyframe PositionDisplay->SetBackgroundColour(Options.AsColour(_T("Grid selection background"))); PositionDisplay->SetForegroundColour(Options.AsColour(_T("Grid selection foreground"))); @@ -178,7 +179,7 @@ void VideoDisplay::SetFrame(int frameNumber) { int startOff = 0; int endOff = 0; - if (AssDialogue *curLine = VideoContext::Get()->curLine) { + if (AssDialogue *curLine = context->curLine) { startOff = time - curLine->Start.GetMS(); endOff = time - curLine->End.GetMS(); } @@ -193,8 +194,11 @@ void VideoDisplay::SetFrame(int frameNumber) { if (IsShownOnScreen() && visual) visual->Refresh(); // Render the new frame - videoOut->InvalidateFrame(); - Render(frameNumber); + if (context->IsLoaded()) { + AegiVideoFrame frame = context->GetFrame(frameNumber); + videoOut->UploadFrameData(frame); + } + Render(); currentFrame = frameNumber; } @@ -205,7 +209,7 @@ void VideoDisplay::SetFrameRange(int from, int to) { /// @brief Render the currently visible frame -void VideoDisplay::Render(int frameNumber) try { +void VideoDisplay::Render() try { if (!IsShownOnScreen()) return; if (!wxIsMainThread()) throw _T("Error: trying to render from non-primary thread"); @@ -275,7 +279,7 @@ void VideoDisplay::Render(int frameNumber) try { glDisable(GL_BLEND); if (glGetError()) throw _T("Error disabling blending."); - videoOut->DisplayFrame(context->GetFrame(frameNumber), frameNumber, sw, sh); + videoOut->Render(sw, sh); DrawTVEffects(); diff --git a/aegisub/src/video_display.h b/aegisub/src/video_display.h index d5d3913b6..9563a07fd 100644 --- a/aegisub/src/video_display.h +++ b/aegisub/src/video_display.h @@ -145,7 +145,7 @@ public: int GetFrame() const { return currentFrame; } void SetFrameRange(int from, int to); - void Render(int frameNumber = -1); + void Render(); void ShowCursor(bool show); void ConvertMouseCoords(int &x,int &y); diff --git a/aegisub/src/video_out_gl.cpp b/aegisub/src/video_out_gl.cpp index 1eeb21c81..47dbec387 100644 --- a/aegisub/src/video_out_gl.cpp +++ b/aegisub/src/video_out_gl.cpp @@ -111,8 +111,7 @@ VideoOutGL::VideoOutGL() textureList(), textureCount(0), textureRows(0), - textureCols(0), - lastFrame(-1) + textureCols(0) { } /// @brief Runtime detection of required OpenGL capabilities @@ -152,7 +151,7 @@ void VideoOutGL::DetectOpenGLCapabilities() { /// @param height The frame's height /// @param format The frame's format /// @param bpp The frame's bytes per pixel -void VideoOutGL::InitTextures(int width, int height, GLenum format, int bpp) { +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) return; wxLogDebug("VideoOutGL::InitTextures: Video size: %dx%d\n", width, height); @@ -222,6 +221,12 @@ void VideoOutGL::InitTextures(int width, int height, GLenum format, int bpp) { ti.texRight = 1.0f - ti.texLeft; ti.texBottom = 1.0f - ti.texTop; + if (flipped) { + float t = ti.texTop; + ti.texTop = ti.texBottom; + ti.texBottom = ti.texTop; + } + // destW/H is the percent of the output which this texture covers ti.destW = float(w) / width; ti.destH = float(h) / height; @@ -258,22 +263,34 @@ void VideoOutGL::InitTextures(int width, int height, GLenum format, int bpp) { frameHeight = height; frameFormat = format; } - -void VideoOutGL::DisplayFrame(const AegiVideoFrame& frame, int frameNumber, int sw, int sh) { +void VideoOutGL::UploadFrameData(const AegiVideoFrame& frame) { if (frame.h == 0 || frame.w == 0) return; - if (frameNumber == -1) frameNumber = lastFrame; - - glEnable(GL_TEXTURE_2D); - if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glEnable(GL_TEXTURE_2d)", err); - GLuint format = frame.invertChannels ? GL_BGRA_EXT : GL_RGBA; - InitTextures(frame.w, frame.h, format, frame.GetBpp(0)); + InitTextures(frame.w, frame.h, format, frame.GetBpp(0), frame.flipped); // Set the row length, needed to be able to upload partial rows glPixelStorei(GL_UNPACK_ROW_LENGTH, frame.w); if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glPixelStorei(GL_UNPACK_ROW_LENGTH, FrameWidth)", err); + for (unsigned i = 0; i < textureList.size(); i++) { + TextureInfo& ti = textureList[i]; + + glBindTexture(GL_TEXTURE_2D, ti.textureID); + if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glBindTexture", err); + + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, ti.sourceW, ti.sourceH, format, GL_UNSIGNED_BYTE, frame.data[0] + ti.dataOffset); + if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glTexSubImage2D", err); + } + + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glPixelStorei(GL_UNPACK_ROW_LENGTH, default)", err); +} + +void VideoOutGL::Render(int sw, int sh) { + glEnable(GL_TEXTURE_2D); + if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glEnable(GL_TEXTURE_2d)", err); + for (unsigned i = 0; i < textureList.size(); i++) { TextureInfo& ti = textureList[i]; @@ -285,40 +302,19 @@ void VideoOutGL::DisplayFrame(const AegiVideoFrame& frame, int frameNumber, int glBindTexture(GL_TEXTURE_2D, ti.textureID); if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glBindTexture", err); - if (lastFrame != frameNumber) { - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, ti.sourceW, ti.sourceH, format, GL_UNSIGNED_BYTE, frame.data[0] + ti.dataOffset); - if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glTexSubImage2D", err); - } - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glColor4f", err); - float top, bottom; - if (frame.flipped) { - top = ti.texBottom; - bottom = ti.texTop; - } - else { - top = ti.texTop; - bottom = ti.texBottom; - } - glBegin(GL_QUADS); - glTexCoord2f(ti.texLeft, top); glVertex2f(destX, destY); - glTexCoord2f(ti.texRight, top); glVertex2f(destX + destW, destY); - glTexCoord2f(ti.texRight, bottom); glVertex2f(destX + destW, destY + destH); - glTexCoord2f(ti.texLeft, bottom); glVertex2f(destX, destY + destH); + 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); glEnd(); if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"GL_QUADS", err); } - - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glPixelStorei(GL_UNPACK_ROW_LENGTH, default)", err); - glDisable(GL_TEXTURE_2D); if (GLenum err = glGetError()) throw VideoOutOpenGLException(L"glDisable(GL_TEXTURE_2d)", err); - - lastFrame = frameNumber; } VideoOutGL::~VideoOutGL() { diff --git a/aegisub/src/video_out_gl.h b/aegisub/src/video_out_gl.h index 17ece0649..24dca22fb 100644 --- a/aegisub/src/video_out_gl.h +++ b/aegisub/src/video_out_gl.h @@ -74,24 +74,20 @@ private: int textureRows; /// The number of columns of textures int textureCols; - /// The frame currently displayed - int lastFrame; void DetectOpenGLCapabilities(); - void InitTextures(int width, int height, GLenum format, int bpp); + void InitTextures(int width, int height, GLenum format, int bpp, bool flipped); VideoOutGL(const VideoOutGL &); VideoOutGL& operator=(const VideoOutGL&); public: - /// @brief Render a frame + /// @brief Set the frame to be displayed when Render() is called /// @param frame The frame to be displayed - /// @param frameNumber The frame number of 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 - void DisplayFrame(const AegiVideoFrame& frame, int frameNumber, int sw, int sh); - - /// @brief Force the redisplay of the frame the next time DisplayFrame is called even if the frame number has not changed - void InvalidateFrame() { lastFrame = -1; } + void Render(int sw, int sh); /// @brief Constructor VideoOutGL();