mirror of https://github.com/odrling/Aegisub
Make the video display use OpenGL display lists, slightly simplifying the code and reducing the amount of state explicitly tracked.
Originally committed to SVN as r4247.
This commit is contained in:
parent
5f82c5bb02
commit
b90fdcc111
|
@ -66,30 +66,11 @@ struct VideoOutGL::TextureInfo {
|
|||
int dataOffset;
|
||||
int sourceH;
|
||||
int sourceW;
|
||||
|
||||
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)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -147,6 +128,8 @@ void VideoOutGL::DetectOpenGLCapabilities() {
|
|||
/// @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, bool flipped) {
|
||||
using namespace std;
|
||||
|
||||
frameFlipped = flipped;
|
||||
// Do nothing if the frame size and format are unchanged
|
||||
if (width == frameWidth && height == frameHeight && format == frameFormat) return;
|
||||
|
@ -168,9 +151,12 @@ void VideoOutGL::InitTextures(int width, int height, GLenum format, int bpp, boo
|
|||
int textureArea = maxTextureSize - 2;
|
||||
textureRows = (int)ceil(double(height) / textureArea);
|
||||
textureCols = (int)ceil(double(width) / textureArea);
|
||||
textureIdList.resize(textureRows * textureCols);
|
||||
textureList.resize(textureRows * textureCols);
|
||||
textureCount = textureRows * textureCols;
|
||||
textureIdList.resize(textureCount);
|
||||
textureList.resize(textureCount);
|
||||
CHECK_INIT_ERROR(glGenTextures(textureIdList.size(), &textureIdList[0]));
|
||||
vector<pair<int, int> > textureSizes;
|
||||
textureSizes.reserve(textureCount);
|
||||
|
||||
/* Unfortunately, we can't simply use one of the two standard ways to do
|
||||
* tiled textures to work around texture size limits in OpenGL, due to our
|
||||
|
@ -195,6 +181,30 @@ void VideoOutGL::InitTextures(int width, int height, GLenum format, int bpp, boo
|
|||
* Width behaves in the same way with respect to left/right edges
|
||||
*/
|
||||
|
||||
// Set up the display list
|
||||
dl = glGenLists(1);
|
||||
glNewList(dl, GL_COMPILE);
|
||||
|
||||
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));
|
||||
|
||||
// Switch to video coordinates
|
||||
CHECK_ERROR(glMatrixMode(GL_PROJECTION));
|
||||
CHECK_ERROR(glLoadIdentity());
|
||||
CHECK_ERROR(glPushMatrix());
|
||||
if (frameFlipped) {
|
||||
CHECK_ERROR(glOrtho(0.0f, frameWidth, 0.0f, frameHeight, -1000.0f, 1000.0f));
|
||||
}
|
||||
else {
|
||||
CHECK_ERROR(glOrtho(0.0f, frameWidth, frameHeight, 0.0f, -1000.0f, 1000.0f));
|
||||
}
|
||||
|
||||
CHECK_ERROR(glEnable(GL_TEXTURE_2D));
|
||||
|
||||
// Calculate the position information for each texture
|
||||
int lastRow = textureRows - 1;
|
||||
int lastCol = textureCols - 1;
|
||||
|
@ -221,32 +231,50 @@ void VideoOutGL::InitTextures(int width, int height, GLenum format, int bpp, boo
|
|||
// Location where this texture is placed
|
||||
// X2/Y2 will be offscreen unless the video frame happens to
|
||||
// exactly use all of the texture
|
||||
ti.destX1 = sourceX + (col != 0);
|
||||
ti.destY1 = sourceY + (row != 0);
|
||||
ti.destX2 = sourceX + textureWidth - (col != lastCol);
|
||||
ti.destY2 = sourceY + textureHeight - (row != lastRow);
|
||||
float x1 = sourceX + (col != 0);
|
||||
float y1 = sourceY + (row != 0);
|
||||
float x2 = sourceX + textureWidth - (col != lastCol);
|
||||
float y2 = sourceY + textureHeight - (row != lastRow);
|
||||
|
||||
// Portion of the texture actually used
|
||||
ti.texTop = row == 0 ? 0 : 1.0f / textureHeight;
|
||||
ti.texLeft = col == 0 ? 0 : 1.0f / textureWidth;
|
||||
ti.texBottom = row == lastRow ? 1.0f : 1.0f - 1.0f / textureHeight;
|
||||
ti.texRight = col == lastCol ? 1.0f : 1.0f - 1.0f / textureWidth;
|
||||
float top = row == 0 ? 0 : 1.0f / textureHeight;
|
||||
float left = col == 0 ? 0 : 1.0f / textureWidth;
|
||||
float bottom = row == lastRow ? 1.0f : 1.0f - 1.0f / textureHeight;
|
||||
float right = col == lastCol ? 1.0f : 1.0f - 1.0f / textureWidth;
|
||||
|
||||
// Store the stuff needed later
|
||||
ti.textureID = textureIdList[row * textureCols + col];
|
||||
textureSizes.push_back(make_pair(textureWidth, textureHeight));
|
||||
|
||||
CreateTexture(textureWidth, textureHeight, ti, format);
|
||||
CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, ti.textureID));
|
||||
CHECK_ERROR(glColor4f(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
|
||||
// Place the texture
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(left, top); glVertex2f(x1, y1);
|
||||
glTexCoord2f(right, top); glVertex2f(x2, y1);
|
||||
glTexCoord2f(right, bottom); glVertex2f(x2, y2);
|
||||
glTexCoord2f(left, bottom); glVertex2f(x1, y2);
|
||||
glEnd();
|
||||
if (GLenum err = glGetError()) throw VideoOutRenderException(L"GL_QUADS", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
CHECK_ERROR(glDisable(GL_TEXTURE_2D));
|
||||
CHECK_ERROR(glPopMatrix());
|
||||
|
||||
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(L"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));
|
||||
CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP));
|
||||
CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP));
|
||||
glEndList();
|
||||
|
||||
// Create the textures outside of the display list as there's no need to
|
||||
// remake them on every frame
|
||||
for (int i = 0; i < textureCount; ++i) {
|
||||
CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, textureIdList[i]));
|
||||
CHECK_INIT_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, textureSizes[i].first, textureSizes[i].second, 0, format, GL_UNSIGNED_BYTE, NULL));
|
||||
wxLogDebug(L"VideoOutGL::InitTextures: Using texture size: %dx%d\n", textureSizes[i].first, textureSizes[i].second);
|
||||
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));
|
||||
CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP));
|
||||
CHECK_INIT_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP));
|
||||
}
|
||||
}
|
||||
|
||||
void VideoOutGL::UploadFrameData(const AegiVideoFrame& frame) {
|
||||
|
@ -273,52 +301,20 @@ void VideoOutGL::SetViewport(int x, int y, int width, int 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));
|
||||
glCallList(dl);
|
||||
|
||||
|
||||
CHECK_ERROR(glShadeModel(GL_FLAT));
|
||||
CHECK_ERROR(glDisable(GL_BLEND));
|
||||
|
||||
CHECK_ERROR(glMatrixMode(GL_PROJECTION));
|
||||
CHECK_ERROR(glLoadIdentity());
|
||||
CHECK_ERROR(glPushMatrix());
|
||||
if (frameFlipped) {
|
||||
CHECK_ERROR(glOrtho(0.0f, frameWidth, 0.0f, frameHeight, -1000.0f, 1000.0f));
|
||||
}
|
||||
else {
|
||||
CHECK_ERROR(glOrtho(0.0f, frameWidth, frameHeight, 0.0f, -1000.0f, 1000.0f));
|
||||
}
|
||||
|
||||
// Render the current frame
|
||||
CHECK_ERROR(glEnable(GL_TEXTURE_2D));
|
||||
|
||||
for (unsigned i = 0; i < textureList.size(); i++) {
|
||||
TextureInfo& ti = textureList[i];
|
||||
|
||||
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(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(glPopMatrix());
|
||||
// Switch to script coordinates
|
||||
// This isn't really the right place to do this, but there isn't really
|
||||
// anywhere better right now
|
||||
CHECK_ERROR(glOrtho(0.0f, sw, sh, 0.0f, -1000.0f, 1000.0f));
|
||||
CHECK_ERROR(glMatrixMode(GL_MODELVIEW));
|
||||
CHECK_ERROR(glLoadIdentity());
|
||||
|
||||
}
|
||||
|
||||
VideoOutGL::~VideoOutGL() {
|
||||
if (textureIdList.size() > 0) {
|
||||
glDeleteTextures(textureIdList.size(), &textureIdList[0]);
|
||||
glDeleteLists(dl, 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,6 +69,8 @@ private:
|
|||
std::vector<GLuint> textureIdList;
|
||||
/// List of precalculated texture display information
|
||||
std::vector<TextureInfo> textureList;
|
||||
/// OpenGL display list which draws the frames
|
||||
GLuint dl;
|
||||
/// The total texture count
|
||||
int textureCount;
|
||||
/// The number of rows of textures
|
||||
|
@ -78,7 +80,6 @@ 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&);
|
||||
|
|
Loading…
Reference in New Issue