Large reorganization of the OpenGL code, separating out FBSurfaces into

distinct GUI vs non-GUI (aka TIA) classes.  This makes it easy to proceed
from this point on, since I don't have to worry about breaking one mode
when making changes to the other.

Preliminary support for TIA scanlines in OpenGL mode.  It's disabled for
now, but is progressing nicely.  This will be part of the new TV effects
in the next major release.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2273 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2011-08-28 21:49:16 +00:00
parent b45d65fc31
commit c2992f5097
8 changed files with 1040 additions and 645 deletions

381
src/common/FBSurfaceGL.cxx Normal file
View File

@ -0,0 +1,381 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2011 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id$
//============================================================================
#ifdef DISPLAY_OPENGL
#include "Font.hxx"
#include "FrameBufferGL.hxx"
#include "FBSurfaceGL.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FBSurfaceGL::FBSurfaceGL(FrameBufferGL& buffer, uInt32 width, uInt32 height)
: myFB(buffer),
myGL(myFB.p_gl),
myTexture(NULL),
myTexID(0),
myVBOID(0),
myImageX(0),
myImageY(0),
myImageW(width),
myImageH(height)
{
// Fill buffer struct with valid data
myTexWidth = FrameBufferGL::power_of_two(myImageW);
myTexHeight = FrameBufferGL::power_of_two(myImageH);
myTexCoordW = (GLfloat) myImageW / myTexWidth;
myTexCoordH = (GLfloat) myImageH / myTexHeight;
// Based on experimentation, the following are the fastest 16-bit
// formats for OpenGL (on all platforms)
myTexture = SDL_CreateRGBSurface(SDL_SWSURFACE,
myTexWidth, myTexHeight, 16,
#ifdef HAVE_GL_BGRA
0x00007c00, 0x000003e0, 0x0000001f, 0x00000000);
#else
0x0000f800, 0x000007c0, 0x0000003e, 0x00000000);
#endif
myPitch = myTexture->pitch >> 1;
// Associate the SDL surface with a GL texture object
updateCoords();
reload();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FBSurfaceGL::~FBSurfaceGL()
{
if(myTexture)
SDL_FreeSurface(myTexture);
free();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::hLine(uInt32 x, uInt32 y, uInt32 x2, uInt32 color)
{
uInt16* buffer = (uInt16*) myTexture->pixels + y * myPitch + x;
while(x++ <= x2)
*buffer++ = (uInt16) myFB.myDefPalette[color];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::vLine(uInt32 x, uInt32 y, uInt32 y2, uInt32 color)
{
uInt16* buffer = (uInt16*) myTexture->pixels + y * myPitch + x;
while(y++ <= y2)
{
*buffer = (uInt16) myFB.myDefPalette[color];
buffer += myPitch;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, uInt32 color)
{
// Fill the rectangle
SDL_Rect tmp;
tmp.x = x;
tmp.y = y;
tmp.w = w;
tmp.h = h;
SDL_FillRect(myTexture, &tmp, myFB.myDefPalette[color]);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::drawChar(const GUI::Font* font, uInt8 chr,
uInt32 tx, uInt32 ty, uInt32 color)
{
const FontDesc& desc = font->desc();
// If this character is not included in the font, use the default char.
if(chr < desc.firstchar || chr >= desc.firstchar + desc.size)
{
if (chr == ' ') return;
chr = desc.defaultchar;
}
chr -= desc.firstchar;
// Get the bounding box of the character
int bbw, bbh, bbx, bby;
if(!desc.bbx)
{
bbw = desc.fbbw;
bbh = desc.fbbh;
bbx = desc.fbbx;
bby = desc.fbby;
}
else
{
bbw = desc.bbx[chr].w;
bbh = desc.bbx[chr].h;
bbx = desc.bbx[chr].x;
bby = desc.bbx[chr].y;
}
const uInt16* tmp = desc.bits + (desc.offset ? desc.offset[chr] : (chr * desc.fbbh));
uInt16* buffer = (uInt16*) myTexture->pixels +
(ty + desc.ascent - bby - bbh) * myPitch +
tx + bbx;
for(int y = 0; y < bbh; y++)
{
const uInt16 ptr = *tmp++;
uInt16 mask = 0x8000;
for(int x = 0; x < bbw; x++, mask >>= 1)
if(ptr & mask)
buffer[x] = (uInt16) myFB.myDefPalette[color];
buffer += myPitch;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::drawBitmap(uInt32* bitmap, uInt32 tx, uInt32 ty,
uInt32 color, uInt32 h)
{
uInt16* buffer = (uInt16*) myTexture->pixels + ty * myPitch + tx;
for(uInt32 y = 0; y < h; ++y)
{
uInt32 mask = 0xF0000000;
for(uInt32 x = 0; x < 8; ++x, mask >>= 4)
if(bitmap[y] & mask)
buffer[x] = (uInt16) myFB.myDefPalette[color];
buffer += myPitch;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::drawPixels(uInt32* data, uInt32 tx, uInt32 ty, uInt32 numpixels)
{
uInt16* buffer = (uInt16*) myTexture->pixels + ty * myPitch + tx;
for(uInt32 i = 0; i < numpixels; ++i)
*buffer++ = (uInt16) data[i];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::drawSurface(const FBSurface* surface, uInt32 tx, uInt32 ty)
{
const FBSurfaceGL* s = (const FBSurfaceGL*) surface;
SDL_Rect dstrect;
dstrect.x = tx;
dstrect.y = ty;
SDL_Rect srcrect;
srcrect.x = 0;
srcrect.y = 0;
srcrect.w = s->myImageW;
srcrect.h = s->myImageH;
SDL_BlitSurface(s->myTexture, &srcrect, myTexture, &dstrect);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::addDirtyRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h)
{
// OpenGL mode doesn't make use of dirty rectangles
// It's faster to just update the entire surface
mySurfaceIsDirty = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::getPos(uInt32& x, uInt32& y) const
{
x = myImageX;
y = myImageY;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::setPos(uInt32 x, uInt32 y)
{
if(myImageX != x || myImageY != y)
{
myImageX = x;
myImageY = y;
updateCoords();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::setWidth(uInt32 w)
{
// This method can't be used with 'scaled' surface (aka TIA surfaces)
// That shouldn't really matter, though, as all the UI stuff isn't scaled,
// and it's the only thing that uses it
if(myImageW != w)
{
myImageW = w;
myTexCoordW = (GLfloat) myImageW / myTexWidth;
updateCoords();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::setHeight(uInt32 h)
{
// This method can't be used with 'scaled' surface (aka TIA surfaces)
// That shouldn't really matter, though, as all the UI stuff isn't scaled,
// and it's the only thing that uses it
if(myImageH != h)
{
myImageH = h;
myTexCoordH = (GLfloat) myImageH / myTexHeight;
updateCoords();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::translateCoords(Int32& x, Int32& y) const
{
x -= myImageX;
y -= myImageY;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::update()
{
if(mySurfaceIsDirty)
{
// Texturemap complete texture to surface so we have free scaling
// and antialiasing
myGL.ActiveTexture(GL_TEXTURE0);
myGL.BindTexture(GL_TEXTURE_2D, myTexID);
myGL.TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, myTexWidth, myTexHeight,
#ifdef HAVE_GL_BGRA
GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV,
#else
GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1,
#endif
myTexture->pixels);
myGL.EnableClientState(GL_VERTEX_ARRAY);
myGL.EnableClientState(GL_TEXTURE_COORD_ARRAY);
if(myFB.myVBOAvailable)
{
myGL.BindBuffer(GL_ARRAY_BUFFER, myVBOID);
myGL.VertexPointer(2, GL_FLOAT, 0, (const GLvoid*)0);
myGL.TexCoordPointer(2, GL_FLOAT, 0, (const GLvoid*)(8*sizeof(GLfloat)));
}
else
{
myGL.VertexPointer(2, GL_FLOAT, 0, myCoord);
myGL.TexCoordPointer(2, GL_FLOAT, 0, myCoord+8);
}
myGL.DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
myGL.DisableClientState(GL_VERTEX_ARRAY);
myGL.DisableClientState(GL_TEXTURE_COORD_ARRAY);
mySurfaceIsDirty = false;
// Let postFrameUpdate() know that a change has been made
myFB.myDirtyFlag = true;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::free()
{
myGL.DeleteTextures(1, &myTexID);
if(myFB.myVBOAvailable)
myGL.DeleteBuffers(1, &myVBOID);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::reload()
{
// This does a 'soft' reset of the surface
// It seems that on some system (notably, OSX), creating a new SDL window
// destroys the GL context, requiring a reload of all textures
// However, destroying the entire FBSurfaceGL object is wasteful, since
// it will also regenerate SDL software surfaces (which are not required
// to be regenerated)
// Basically, all that needs to be done is to re-call glTexImage2D with a
// new texture ID, so that's what we do here
myGL.ActiveTexture(GL_TEXTURE0);
myGL.Enable(GL_TEXTURE_2D);
myGL.GenTextures(1, &myTexID);
myGL.BindTexture(GL_TEXTURE_2D, myTexID);
myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Create the texture in the most optimal format
myGL.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
myTexWidth, myTexHeight, 0,
#ifdef HAVE_GL_BGRA
GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV,
#else
GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1,
#endif
myTexture->pixels);
// Cache vertex and texture coordinates using vertex buffer object
if(myFB.myVBOAvailable)
{
myGL.GenBuffers(1, &myVBOID);
myGL.BindBuffer(GL_ARRAY_BUFFER, myVBOID);
myGL.BufferData(GL_ARRAY_BUFFER, 16*sizeof(GLfloat), myCoord, GL_STATIC_DRAW);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::updateCoords()
{
// Vertex coordinates for texture
// Upper left (x,y)
myCoord[0] = (GLfloat)myImageX;
myCoord[1] = (GLfloat)myImageY;
// Upper right (x+w,y)
myCoord[2] = (GLfloat)(myImageX + myImageW);
myCoord[3] = (GLfloat)myImageY;
// Lower left (x,y+h)
myCoord[4] = (GLfloat)myImageX;
myCoord[5] = (GLfloat)(myImageY + myImageH);
// Lower right (x+w,y+h)
myCoord[6] = (GLfloat)(myImageX + myImageW);
myCoord[7] = (GLfloat)(myImageY + myImageH);
// Texture coordinates for texture
// Upper left (x,y)
myCoord[8] = 0.0f;
myCoord[9] = 0.0f;
// Upper right (x+w,y)
myCoord[10] = myTexCoordW;
myCoord[11] = 0.0f;
// Lower left (x,y+h)
myCoord[12] = 0.0f;
myCoord[13] = myTexCoordH;
// Lower right (x+w,y+h)
myCoord[14] = myTexCoordW;
myCoord[15] = myTexCoordH;
// Cache vertex and texture coordinates using vertex buffer object
if(myFB.myVBOAvailable)
{
myGL.BindBuffer(GL_ARRAY_BUFFER, myVBOID);
myGL.BufferData(GL_ARRAY_BUFFER, 16*sizeof(GLfloat), myCoord, GL_STATIC_DRAW);
}
}
#endif

View File

@ -0,0 +1,84 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2011 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id$
//============================================================================
#ifndef FB_SURFACE_GL_HXX
#define FB_SURFACE_GL_HXX
#ifdef DISPLAY_OPENGL
#include "bspf.hxx"
#include "FrameBuffer.hxx"
#include "FrameBufferGL.hxx"
/**
A surface suitable for OpenGL rendering mode, used for various UI dialogs.
This class extends FrameBuffer::FBSurface.
@author Stephen Anthony
*/
class FBSurfaceGL : public FBSurface
{
friend class FrameBufferGL;
public:
FBSurfaceGL(FrameBufferGL& buffer, uInt32 width, uInt32 height);
virtual ~FBSurfaceGL();
// Normal surfaces need all drawing primitives
void hLine(uInt32 x, uInt32 y, uInt32 x2, uInt32 color);
void vLine(uInt32 x, uInt32 y, uInt32 y2, uInt32 color);
void fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, uInt32 color);
void drawChar(const GUI::Font* font, uInt8 c, uInt32 x, uInt32 y, uInt32 color);
void drawBitmap(uInt32* bitmap, uInt32 x, uInt32 y, uInt32 color, uInt32 h = 8);
void drawPixels(uInt32* data, uInt32 x, uInt32 y, uInt32 numpixels);
void drawSurface(const FBSurface* surface, uInt32 x, uInt32 y);
void addDirtyRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h);
void getPos(uInt32& x, uInt32& y) const;
void setPos(uInt32 x, uInt32 y);
uInt32 getWidth() const { return myImageW; }
uInt32 getHeight() const { return myImageH; }
void setWidth(uInt32 w);
void setHeight(uInt32 h);
void translateCoords(Int32& x, Int32& y) const;
void update();
void free();
void reload();
private:
void updateCoords();
private:
FrameBufferGL& myFB;
const FrameBufferGL::GLpointers& myGL;
SDL_Surface* myTexture;
GLuint myTexID, myVBOID;
GLsizei myTexWidth;
GLsizei myTexHeight;
GLuint myImageX, myImageY, myImageW, myImageH;
GLfloat myTexCoordW, myTexCoordH;
GLfloat myCoord[16];
bool mySurfaceIsDirty;
uInt32 myPitch;
};
#endif // DISPLAY_OPENGL
#endif

348
src/common/FBSurfaceTIA.cxx Normal file
View File

@ -0,0 +1,348 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2011 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id$
//============================================================================
#ifdef DISPLAY_OPENGL
#include "Font.hxx"
#include "FrameBufferGL.hxx"
#include "TIA.hxx"
#include "FBSurfaceTIA.hxx"
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FBSurfaceTIA::FBSurfaceTIA(FrameBufferGL& buffer, uInt32 baseWidth, uInt32 baseHeight,
uInt32 imgX, uInt32 imgY, uInt32 imgW, uInt32 imgH)
: myFB(buffer),
myGL(myFB.p_gl),
myTexture(NULL),
myVBOID(0),
myImageX(imgX),
myImageY(imgY),
myImageW(imgW),
myImageH(imgH)
{
myTexID[0] = myTexID[1] = 0;
// Fill buffer struct with valid data
myTexWidth = FrameBufferGL::power_of_two(baseWidth);
myTexHeight = FrameBufferGL::power_of_two(baseHeight);
myTexCoordW = (GLfloat) baseWidth / myTexWidth;
myTexCoordH = (GLfloat) baseHeight / myTexHeight;
// Based on experimentation, the following are the fastest 16-bit
// formats for OpenGL (on all platforms)
myTexture = SDL_CreateRGBSurface(SDL_SWSURFACE,
myTexWidth, myTexHeight, 16,
#ifdef HAVE_GL_BGRA
0x00007c00, 0x000003e0, 0x0000001f, 0x00000000);
#else
0x0000f800, 0x000007c0, 0x0000003e, 0x00000000);
#endif
myPitch = myTexture->pitch >> 1;
// Associate the SDL surface with a GL texture object
updateCoords();
reload();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FBSurfaceTIA::~FBSurfaceTIA()
{
if(myTexture)
SDL_FreeSurface(myTexture);
free();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceTIA::getPos(uInt32& x, uInt32& y) const
{
x = myImageX;
y = myImageY;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceTIA::translateCoords(Int32& x, Int32& y) const
{
x -= myImageX;
y -= myImageY;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceTIA::update()
{
// Copy the mediasource framebuffer to the RGB texture
// In OpenGL mode, it's faster to just assume that the screen is dirty
// and always do an update
uInt8* currentFrame = myTIA->currentFrameBuffer();
uInt8* previousFrame = myTIA->previousFrameBuffer();
uInt32 width = myTIA->width();
uInt32 height = myTIA->height();
uInt16* buffer = (uInt16*) myTexture->pixels;
if(!myFB.myUsePhosphor)
{
uInt32 bufofsY = 0;
uInt32 screenofsY = 0;
for(uInt32 y = 0; y < height; ++y )
{
uInt32 pos = screenofsY;
for(uInt32 x = 0; x < width; ++x )
buffer[pos++] = (uInt16) myFB.myDefPalette[currentFrame[bufofsY + x]];
bufofsY += width;
screenofsY += myPitch;
}
}
else
{
uInt32 bufofsY = 0;
uInt32 screenofsY = 0;
for(uInt32 y = 0; y < height; ++y )
{
uInt32 pos = screenofsY;
for(uInt32 x = 0; x < width; ++x )
{
const uInt32 bufofs = bufofsY + x;
buffer[pos++] = (uInt16)
myFB.myAvgPalette[currentFrame[bufofs]][previousFrame[bufofs]];
}
bufofsY += width;
screenofsY += myPitch;
}
}
// Texturemap complete texture to surface so we have free scaling
// and antialiasing
myGL.ActiveTexture(GL_TEXTURE0);
myGL.BindTexture(GL_TEXTURE_2D, myTexID[0]);
myGL.TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, myTexWidth, myTexHeight,
#ifdef HAVE_GL_BGRA
GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV,
#else
GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1,
#endif
myTexture->pixels);
myGL.EnableClientState(GL_VERTEX_ARRAY);
myGL.EnableClientState(GL_TEXTURE_COORD_ARRAY);
if(myFB.myVBOAvailable)
{
myGL.BindBuffer(GL_ARRAY_BUFFER, myVBOID);
myGL.VertexPointer(2, GL_FLOAT, 0, (const GLvoid*)0);
myGL.TexCoordPointer(2, GL_FLOAT, 0, (const GLvoid*)(8*sizeof(GLfloat)));
myGL.DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
#if 0
if(1)//myFB.myScanlinesEnabled)
{
myGL.Enable(GL_BLEND);
myGL.Color4f(1.0f, 1.0f, 1.0f, 0.5f);
myGL.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
myGL.BindTexture(GL_TEXTURE_2D, myTexID[1]);
myGL.VertexPointer(2, GL_FLOAT, 0, (const GLvoid*)(16*sizeof(GLfloat)));
myGL.TexCoordPointer(2, GL_FLOAT, 0, (const GLvoid*)(24*sizeof(GLfloat)));
myGL.DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
myGL.Disable(GL_BLEND);
}
#endif
}
else
{
myGL.VertexPointer(2, GL_FLOAT, 0, myCoord);
myGL.TexCoordPointer(2, GL_FLOAT, 0, myCoord+8);
myGL.DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
#if 0
if(1)//myFB.myScanlinesEnabled)
{
myGL.Enable(GL_BLEND);
myGL.Color4f(1.0f, 1.0f, 1.0f, 0.5f);
myGL.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
myGL.BindTexture(GL_TEXTURE_2D, myTexID[1]);
myGL.VertexPointer(2, GL_FLOAT, 0, myCoord+16);
myGL.TexCoordPointer(2, GL_FLOAT, 0, myCoord+24);
myGL.DrawArrays(GL_TRIANGLE_STRIP, 0, 4);
myGL.Disable(GL_BLEND);
}
#endif
}
myGL.DisableClientState(GL_VERTEX_ARRAY);
myGL.DisableClientState(GL_TEXTURE_COORD_ARRAY);
// Let postFrameUpdate() know that a change has been made
myFB.myDirtyFlag = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceTIA::free()
{
myGL.DeleteTextures(2, myTexID);
if(myFB.myVBOAvailable)
myGL.DeleteBuffers(1, &myVBOID);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceTIA::reload()
{
// This does a 'soft' reset of the surface
// It seems that on some system (notably, OSX), creating a new SDL window
// destroys the GL context, requiring a reload of all textures
// However, destroying the entire FBSurfaceGL object is wasteful, since
// it will also regenerate SDL software surfaces (which are not required
// to be regenerated)
// Basically, all that needs to be done is to re-call glTexImage2D with a
// new texture ID, so that's what we do here
myGL.ActiveTexture(GL_TEXTURE0);
myGL.Enable(GL_TEXTURE_2D);
// TIA surfaces also use a scanline texture
myGL.GenTextures(2, myTexID);
// Base texture (@ index 0)
myGL.BindTexture(GL_TEXTURE_2D, myTexID[0]);
myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// Create the texture in the most optimal format
myGL.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
myTexWidth, myTexHeight, 0,
#ifdef HAVE_GL_BGRA
GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV,
#else
GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1,
#endif
myTexture->pixels);
// Scanline texture (@ index 1)
myGL.BindTexture(GL_TEXTURE_2D, myTexID[1]);
myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
#ifdef HAVE_GL_BGRA
static uInt16 const scanline[4] = { 0x0000, 0x0000, 0x8000, 0x0000 };
myGL.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 2, 0,
GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV,
scanline);
#else
static uInt16 const scanline[4] = { 0x0000, 0x0000, 0x0001, 0x0000 };
myGL.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 2, 0,
GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1,
scanline);
#endif
// Cache vertex and texture coordinates using vertex buffer object
if(myFB.myVBOAvailable)
{
myGL.GenBuffers(1, &myVBOID);
myGL.BindBuffer(GL_ARRAY_BUFFER, myVBOID);
myGL.BufferData(GL_ARRAY_BUFFER, 32*sizeof(GLfloat), myCoord, GL_STATIC_DRAW);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceTIA::setFilter(const string& name)
{
// We only do GL_NEAREST or GL_LINEAR for now
GLint filter = GL_NEAREST;
if(name == "linear")
filter = GL_LINEAR;
myGL.BindTexture(GL_TEXTURE_2D, myTexID[0]);
myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
myGL.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceTIA::updateCoords()
{
// Vertex coordinates for texture 0 (main texture)
// Upper left (x,y)
myCoord[0] = (GLfloat)myImageX;
myCoord[1] = (GLfloat)myImageY;
// Upper right (x+w,y)
myCoord[2] = (GLfloat)(myImageX + myImageW);
myCoord[3] = (GLfloat)myImageY;
// Lower left (x,y+h)
myCoord[4] = (GLfloat)myImageX;
myCoord[5] = (GLfloat)(myImageY + myImageH);
// Lower right (x+w,y+h)
myCoord[6] = (GLfloat)(myImageX + myImageW);
myCoord[7] = (GLfloat)(myImageY + myImageH);
// Texture coordinates for texture 0 (main texture)
// Upper left (x,y)
myCoord[8] = 0.0f;
myCoord[9] = 0.0f;
// Upper right (x+w,y)
myCoord[10] = myTexCoordW;
myCoord[11] = 0.0f;
// Lower left (x,y+h)
myCoord[12] = 0.0f;
myCoord[13] = myTexCoordH;
// Lower right (x+w,y+h)
myCoord[14] = myTexCoordW;
myCoord[15] = myTexCoordH;
// Vertex coordinates for texture 1 (scanline texture)
// Upper left (x,y)
myCoord[16] = (GLfloat)myImageX;
myCoord[17] = (GLfloat)myImageY;
// Upper right (x+w,y)
myCoord[18] = (GLfloat)(myImageX + myImageW);
myCoord[19] = (GLfloat)myImageY;
// Lower left (x,y+h)
myCoord[20] = (GLfloat)myImageX;
myCoord[21] = (GLfloat)(myImageY + myImageH);
// Lower right (x+w,y+h)
myCoord[22] = (GLfloat)(myImageX + myImageW);
myCoord[23] = (GLfloat)(myImageY + myImageH);
// Texture coordinates for texture 1 (scanline texture)
// Upper left (x,y)
myCoord[24] = 0.0f;
myCoord[25] = 0.0f;
// Upper right (x+w,y)
myCoord[26] = 1.0f;
myCoord[27] = 0.0f;
// Lower left (x,y+h)
myCoord[28] = 0.0f;
myCoord[29] = (GLfloat)(myImageH/myFB.myZoomLevel);
// Lower right (x+w,y+h)
myCoord[30] = 1.0f;
myCoord[31] = (GLfloat)(myImageH/myFB.myZoomLevel);
// Cache vertex and texture coordinates using vertex buffer object
if(myFB.myVBOAvailable)
{
myGL.BindBuffer(GL_ARRAY_BUFFER, myVBOID);
myGL.BufferData(GL_ARRAY_BUFFER, 32*sizeof(GLfloat), myCoord, GL_STATIC_DRAW);
}
}
#endif

View File

@ -0,0 +1,79 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2011 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//
// $Id$
//============================================================================
#ifndef FB_SURFACE_TIA_HXX
#define FB_SURFACE_TIA_HXX
#ifdef DISPLAY_OPENGL
#include "bspf.hxx"
#include "FrameBuffer.hxx"
#include "FrameBufferGL.hxx"
/**
A surface suitable for OpenGL rendering mode, but specifically for
rendering from a TIA source. It doesn't implement most of the
drawing primitives, since it's concerned with TIA images only.
This class extends FrameBuffer::FBSurface.
@author Stephen Anthony
*/
class FBSurfaceTIA : public FBSurface
{
friend class FrameBufferGL;
public:
FBSurfaceTIA(FrameBufferGL& buffer, uInt32 baseWidth, uInt32 baseHeight,
uInt32 imgX, uInt32 imgY, uInt32 imgW, uInt32 imgH);
virtual ~FBSurfaceTIA();
// TIA surfaces don't implement most of the drawing primitives,
// only the methods absolutely necessary for dealing with drawing
// a TIA image
void getPos(uInt32& x, uInt32& y) const;
uInt32 getWidth() const { return myImageW; }
uInt32 getHeight() const { return myImageH; }
void translateCoords(Int32& x, Int32& y) const;
void update();
void free();
void reload();
private:
void setTIA(const TIA& tia) { myTIA = &tia; }
void setFilter(const string& name);
void updateCoords();
private:
FrameBufferGL& myFB;
const FrameBufferGL::GLpointers& myGL;
const TIA* myTIA;
SDL_Surface* myTexture;
uInt32 myPitch;
GLuint myTexID[2], myVBOID;
GLsizei myTexWidth;
GLsizei myTexHeight;
GLuint myImageX, myImageY, myImageW, myImageH;
GLfloat myTexCoordW, myTexCoordH;
GLfloat myCoord[32];
};
#endif // DISPLAY_OPENGL
#endif

View File

@ -33,43 +33,10 @@
#include "Settings.hxx"
#include "TIA.hxx"
#include "FBSurfaceGL.hxx"
#include "FBSurfaceTIA.hxx"
#include "FrameBufferGL.hxx"
// OpenGL functions we'll be using in Stella
#define OGL_DECLARE(RET,FUNC,PARAMS) static RET (APIENTRY* p_ ## FUNC) PARAMS
OGL_DECLARE(void,glClear,(GLbitfield));
OGL_DECLARE(void,glEnable,(GLenum));
OGL_DECLARE(void,glDisable,(GLenum));
OGL_DECLARE(void,glPushAttrib,(GLbitfield));
OGL_DECLARE(const GLubyte*,glGetString,(GLenum));
OGL_DECLARE(void,glHint,(GLenum, GLenum));
OGL_DECLARE(void,glShadeModel,(GLenum));
OGL_DECLARE(void,glMatrixMode,(GLenum));
OGL_DECLARE(void,glOrtho,(GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble));
OGL_DECLARE(void,glViewport,(GLint, GLint, GLsizei, GLsizei));
OGL_DECLARE(void,glLoadIdentity,(void));
OGL_DECLARE(void,glEnableClientState,(GLenum));
OGL_DECLARE(void,glDisableClientState,(GLenum));
OGL_DECLARE(void,glVertexPointer,(GLint,GLenum,GLsizei,const GLvoid*));
OGL_DECLARE(void,glTexCoordPointer,(GLint,GLenum,GLsizei,const GLvoid*));
OGL_DECLARE(void,glDrawArrays,(GLenum,GLint,GLsizei));
OGL_DECLARE(void,glReadPixels,(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoid*));
OGL_DECLARE(void,glPixelStorei,(GLenum, GLint));
OGL_DECLARE(void,glTexEnvf,(GLenum, GLenum, GLfloat));
OGL_DECLARE(void,glGenTextures,(GLsizei, GLuint*));
OGL_DECLARE(void,glDeleteTextures,(GLsizei, const GLuint*));
OGL_DECLARE(void,glActiveTexture,(GLenum));
OGL_DECLARE(void,glBindTexture,(GLenum, GLuint));
OGL_DECLARE(void,glTexImage2D,(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*));
OGL_DECLARE(void,glTexSubImage2D,(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid*));
OGL_DECLARE(void,glTexParameteri,(GLenum, GLenum, GLint));
OGL_DECLARE(GLenum,glGetError,(void));
OGL_DECLARE(void,glGenBuffers,(GLsizei,GLuint*));
OGL_DECLARE(void,glBindBuffer,(GLenum,GLuint));
OGL_DECLARE(void,glBufferData,(GLenum,GLsizei,const void*,GLenum));
OGL_DECLARE(void,glDeleteBuffers,(GLsizei, const GLuint*));
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FrameBufferGL::FrameBufferGL(OSystem* osystem)
: FrameBuffer(osystem),
@ -82,7 +49,7 @@ FrameBufferGL::FrameBufferGL(OSystem* osystem)
// since the structure may be needed before any FBSurface's have
// been created
SDL_Surface* s = SDL_CreateRGBSurface(SDL_SWSURFACE, 1, 1, 16,
#if defined(GL_BGRA) && defined(GL_UNSIGNED_SHORT_1_5_5_5_REV)
#ifdef HAVE_GL_BGRA
0x00007c00, 0x000003e0, 0x0000001f, 0x00000000);
#else
0x0000f800, 0x000007c0, 0x0000003e, 0x00000000);
@ -117,8 +84,8 @@ bool FrameBufferGL::loadLibrary(const string& library)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool FrameBufferGL::loadFuncs(GLFunctionality functionality)
{
#define OGL_INIT(RET,FUNC,PARAMS) \
p_ ## FUNC = (RET(APIENTRY*)PARAMS) SDL_GL_GetProcAddress(#FUNC); if(!p_ ## FUNC) return false
#define OGL_INIT(NAME,RET,FUNC,PARAMS) \
p_gl.NAME = (RET(APIENTRY*)PARAMS) SDL_GL_GetProcAddress(#FUNC); if(!p_gl.NAME) return false
if(myLibraryLoaded)
{
@ -127,44 +94,42 @@ bool FrameBufferGL::loadFuncs(GLFunctionality functionality)
switch(functionality)
{
case kGL_BASIC:
OGL_INIT(void,glClear,(GLbitfield));
OGL_INIT(void,glEnable,(GLenum));
OGL_INIT(void,glDisable,(GLenum));
OGL_INIT(void,glPushAttrib,(GLbitfield));
OGL_INIT(const GLubyte*,glGetString,(GLenum));
OGL_INIT(void,glHint,(GLenum, GLenum));
OGL_INIT(void,glShadeModel,(GLenum));
OGL_INIT(void,glMatrixMode,(GLenum));
OGL_INIT(void,glOrtho,(GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble));
OGL_INIT(void,glViewport,(GLint, GLint, GLsizei, GLsizei));
OGL_INIT(void,glLoadIdentity,(void));
OGL_INIT(void,glEnableClientState,(GLenum));
OGL_INIT(void,glDisableClientState,(GLenum));
OGL_INIT(void,glVertexPointer,(GLint,GLenum,GLsizei,const GLvoid*));
OGL_INIT(void,glTexCoordPointer,(GLint,GLenum,GLsizei,const GLvoid*));
OGL_INIT(void,glDrawArrays,(GLenum,GLint,GLsizei));
OGL_INIT(GLenum,glGetError,(void));
OGL_INIT(void,glReadPixels,(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoid*));
OGL_INIT(void,glPixelStorei,(GLenum, GLint));
OGL_INIT(void,glTexEnvf,(GLenum, GLenum, GLfloat));
OGL_INIT(void,glGenTextures,(GLsizei, GLuint*));
OGL_INIT(void,glDeleteTextures,(GLsizei, const GLuint*));
OGL_INIT(void,glActiveTexture,(GLenum));
OGL_INIT(void,glBindTexture,(GLenum, GLuint));
OGL_INIT(void,glTexImage2D,(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*));
OGL_INIT(void,glTexSubImage2D,(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid*));
OGL_INIT(void,glTexParameteri,(GLenum, GLenum, GLint));
OGL_INIT(Clear,void,glClear,(GLbitfield));
OGL_INIT(Enable,void,glEnable,(GLenum));
OGL_INIT(Disable,void,glDisable,(GLenum));
OGL_INIT(PushAttrib,void,glPushAttrib,(GLbitfield));
OGL_INIT(GetString,const GLubyte*,glGetString,(GLenum));
OGL_INIT(Hint,void,glHint,(GLenum, GLenum));
OGL_INIT(ShadeModel,void,glShadeModel,(GLenum));
OGL_INIT(MatrixMode,void,glMatrixMode,(GLenum));
OGL_INIT(Ortho,void,glOrtho,(GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble));
OGL_INIT(Viewport,void,glViewport,(GLint, GLint, GLsizei, GLsizei));
OGL_INIT(LoadIdentity,void,glLoadIdentity,(void));
OGL_INIT(EnableClientState,void,glEnableClientState,(GLenum));
OGL_INIT(DisableClientState,void,glDisableClientState,(GLenum));
OGL_INIT(VertexPointer,void,glVertexPointer,(GLint,GLenum,GLsizei,const GLvoid*));
OGL_INIT(TexCoordPointer,void,glTexCoordPointer,(GLint,GLenum,GLsizei,const GLvoid*));
OGL_INIT(DrawArrays,void,glDrawArrays,(GLenum,GLint,GLsizei));
OGL_INIT(ReadPixels,void,glReadPixels,(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoid*));
OGL_INIT(PixelStorei,void,glPixelStorei,(GLenum, GLint));
OGL_INIT(TexEnvf,void,glTexEnvf,(GLenum, GLenum, GLfloat));
OGL_INIT(GenTextures,void,glGenTextures,(GLsizei, GLuint*));
OGL_INIT(DeleteTextures,void,glDeleteTextures,(GLsizei, const GLuint*));
OGL_INIT(ActiveTexture,void,glActiveTexture,(GLenum));
OGL_INIT(BindTexture,void,glBindTexture,(GLenum, GLuint));
OGL_INIT(TexImage2D,void,glTexImage2D,(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*));
OGL_INIT(TexSubImage2D,void,glTexSubImage2D,(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid*));
OGL_INIT(TexParameteri,void,glTexParameteri,(GLenum, GLenum, GLint));
OGL_INIT(GetError,GLenum,glGetError,(void));
OGL_INIT(Color4f,void,glColor4f,(GLfloat,GLfloat,GLfloat,GLfloat));
OGL_INIT(BlendFunc,void,glBlendFunc,(GLenum,GLenum));
break; // kGL_Full
case kGL_VBO:
OGL_INIT(void,glGenBuffers,(GLsizei,GLuint*));
OGL_INIT(void,glBindBuffer,(GLenum,GLuint));
OGL_INIT(void,glBufferData,(GLenum,GLsizei,const void*,GLenum));
OGL_INIT(void,glDeleteBuffers,(GLsizei, const GLuint*));
OGL_INIT(GenBuffers,void,glGenBuffers,(GLsizei,GLuint*));
OGL_INIT(BindBuffer,void,glBindBuffer,(GLenum,GLuint));
OGL_INIT(BufferData,void,glBufferData,(GLenum,GLsizei,const void*,GLenum));
OGL_INIT(DeleteBuffers,void,glDeleteBuffers,(GLsizei, const GLuint*));
break; // kGL_VBO
case kGL_FBO:
@ -218,12 +183,12 @@ string FrameBufferGL::about() const
{
ostringstream out;
out << "Video rendering: OpenGL mode" << endl
<< " Vendor: " << p_glGetString(GL_VENDOR) << endl
<< " Renderer: " << p_glGetString(GL_RENDERER) << endl
<< " Version: " << p_glGetString(GL_VERSION) << endl
<< " Vendor: " << p_gl.GetString(GL_VENDOR) << endl
<< " Renderer: " << p_gl.GetString(GL_RENDERER) << endl
<< " Version: " << p_gl.GetString(GL_VERSION) << endl
<< " Color: " << myDepth << " bit, " << myRGB[0] << "-"
<< myRGB[1] << "-" << myRGB[2] << "-" << myRGB[3] << ", "
#if defined(GL_BGRA) && defined(GL_UNSIGNED_SHORT_1_5_5_5_REV)
#ifdef HAVE_GL_BGRA
<< "GL_BGRA" << endl
#else
<< "GL_RGBA" << endl
@ -311,7 +276,7 @@ bool FrameBufferGL::setVidMode(VideoMode& mode)
if(loadFuncs(kGL_BASIC))
{
// Grab OpenGL version number
string version((const char *)p_glGetString(GL_VERSION));
string version((const char *)p_gl.GetString(GL_VERSION));
myGLVersion = atof(version.substr(0, 3).c_str());
myVBOAvailable = myOSystem->settings().getBool("gl_vbo") && loadFuncs(kGL_VBO);
@ -321,21 +286,20 @@ bool FrameBufferGL::setVidMode(VideoMode& mode)
return false;
// Optimization hints
// TODO - more testing required for OpenGL ES
p_glShadeModel(GL_FLAT);
p_glDisable(GL_CULL_FACE);
p_glDisable(GL_DEPTH_TEST);
p_glDisable(GL_ALPHA_TEST);
p_glDisable(GL_LIGHTING);
p_glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
p_gl.ShadeModel(GL_FLAT);
p_gl.Disable(GL_CULL_FACE);
p_gl.Disable(GL_DEPTH_TEST);
p_gl.Disable(GL_ALPHA_TEST);
p_gl.Disable(GL_LIGHTING);
p_gl.Hint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
// Initialize GL display
p_glViewport(0, 0, mode.screen_w, mode.screen_h);
p_glMatrixMode(GL_PROJECTION);
p_glLoadIdentity();
p_glOrtho(0.0, mode.screen_w, mode.screen_h, 0.0, -1.0, 1.0);
p_glMatrixMode(GL_MODELVIEW);
p_glLoadIdentity();
p_gl.Viewport(0, 0, mode.screen_w, mode.screen_h);
p_gl.MatrixMode(GL_PROJECTION);
p_gl.LoadIdentity();
p_gl.Ortho(0.0, mode.screen_w, mode.screen_h, 0.0, -1.0, 1.0);
p_gl.MatrixMode(GL_MODELVIEW);
p_gl.LoadIdentity();
/*
cerr << "dimensions: " << (fullScreen() ? "(full)" : "") << endl
@ -386,11 +350,11 @@ cerr << "dimensions: " << (fullScreen() ? "(full)" : "") << endl
// Also note that TV filtering is always available since we'll always
// have access to Blargg filtering
if(!myTiaSurface)
myTiaSurface = new FBSurfaceGL(*this, baseWidth>>1, baseHeight,
mode.image_w, mode.image_h, true);
myTiaSurface = new FBSurfaceTIA(*this, baseWidth>>1, baseHeight,
mode.image_x, mode.image_y, mode.image_w, mode.image_h);
myTiaSurface->setPos(mode.image_x, mode.image_y);
myTiaSurface->setFilter(myOSystem->settings().getString("gl_filter"));
myTiaSurface->setTIA(myOSystem->console().tia());
}
return true;
@ -399,77 +363,13 @@ cerr << "dimensions: " << (fullScreen() ? "(full)" : "") << endl
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferGL::invalidate()
{
p_glClear(GL_COLOR_BUFFER_BIT);
p_gl.Clear(GL_COLOR_BUFFER_BIT);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FrameBufferGL::drawTIA(bool fullRedraw)
{
const TIA& tia = myOSystem->console().tia();
// Copy the mediasource framebuffer to the RGB texture
uInt8* currentFrame = tia.currentFrameBuffer();
uInt8* previousFrame = tia.previousFrameBuffer();
uInt32 width = tia.width();
uInt32 height = tia.height();
uInt32 pitch = myTiaSurface->pitch();
uInt16* buffer = (uInt16*) myTiaSurface->pixels();
// TODO - is this fast enough?
if(!myUsePhosphor)
{
uInt32 bufofsY = 0;
uInt32 screenofsY = 0;
for(uInt32 y = 0; y < height; ++y )
{
uInt32 pos = screenofsY;
for(uInt32 x = 0; x < width; ++x )
{
const uInt32 bufofs = bufofsY + x;
uInt8 v = currentFrame[bufofs];
uInt8 w = previousFrame[bufofs];
if(v != w || fullRedraw)
{
// If we ever get to this point, we know the current and previous
// buffers differ. In that case, make sure the changes are
// are drawn in postFrameUpdate()
myDirtyFlag = true;
buffer[pos] = (uInt16) myDefPalette[v];
}
pos++;
}
bufofsY += width;
screenofsY += pitch;
}
}
else
{
// Phosphor mode always implies a dirty update,
// so we don't care about fullRedraw
myDirtyFlag = true;
uInt32 bufofsY = 0;
uInt32 screenofsY = 0;
for(uInt32 y = 0; y < height; ++y )
{
uInt32 pos = screenofsY;
for(uInt32 x = 0; x < width; ++x )
{
const uInt32 bufofs = bufofsY + x;
uInt8 v = currentFrame[bufofs];
uInt8 w = previousFrame[bufofs];
buffer[pos++] = (uInt16) myAvgPalette[v][w];
}
bufofsY += width;
screenofsY += pitch;
}
}
// And blit the surface
myTiaSurface->addDirtyRect(0, 0, 0, 0);
// The TIA surface takes all responsibility for drawing
myTiaSurface->update();
}
@ -497,10 +397,9 @@ void FrameBufferGL::enablePhosphor(bool enable, int blend)
FBSurface* FrameBufferGL::createSurface(int w, int h, bool isBase) const
{
// Ignore 'isBase' argument; all GL surfaces are separate
// Also, since this method will only be called for use in external
// dialogs which cannot be scaled, the base and scaled parameters
// are equal
return new FBSurfaceGL((FrameBufferGL&)*this, w, h, w, h, false);
// Also, this method will only be called for use in external dialogs.
// and never used for TIA surfaces
return new FBSurfaceGL((FrameBufferGL&)*this, w, h);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -511,389 +410,8 @@ void FrameBufferGL::scanline(uInt32 row, uInt8* data) const
const GUI::Rect& image = imageRect();
row = image.height() + image.y() - row - 1;
p_glPixelStorei(GL_PACK_ALIGNMENT, 1);
p_glReadPixels(image.x(), row, image.width(), 1, GL_RGB, GL_UNSIGNED_BYTE, data);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// FBSurfaceGL implementation follows ...
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FBSurfaceGL::FBSurfaceGL(FrameBufferGL& buffer,
uInt32 baseWidth, uInt32 baseHeight,
uInt32 scaleWidth, uInt32 scaleHeight,
bool allowFiltering)
: myFB(buffer),
myTexture(NULL),
myTexID(0),
myVBOID(0),
myXOrig(0),
myYOrig(0),
myWidth(scaleWidth),
myHeight(scaleHeight)
{
// Fill buffer struct with valid data
myTexWidth = power_of_two(baseWidth);
myTexHeight = power_of_two(baseHeight);
myTexCoordW = (GLfloat) baseWidth / myTexWidth;
myTexCoordH = (GLfloat) baseHeight / myTexHeight;
// Based on experimentation, the following are the fastest 16-bit
// formats for OpenGL (on all platforms)
myTexture = SDL_CreateRGBSurface(SDL_SWSURFACE,
myTexWidth, myTexHeight, 16,
#if defined(GL_BGRA) && defined(GL_UNSIGNED_SHORT_1_5_5_5_REV)
0x00007c00, 0x000003e0, 0x0000001f, 0x00000000);
#else
0x0000f800, 0x000007c0, 0x0000003e, 0x00000000);
#endif
myPitch = myTexture->pitch >> 1;
// Associate the SDL surface with a GL texture object
updateCoords();
reload();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FBSurfaceGL::~FBSurfaceGL()
{
if(myTexture)
SDL_FreeSurface(myTexture);
free();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::hLine(uInt32 x, uInt32 y, uInt32 x2, uInt32 color)
{
uInt16* buffer = (uInt16*) myTexture->pixels + y * myPitch + x;
while(x++ <= x2)
*buffer++ = (uInt16) myFB.myDefPalette[color];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::vLine(uInt32 x, uInt32 y, uInt32 y2, uInt32 color)
{
uInt16* buffer = (uInt16*) myTexture->pixels + y * myPitch + x;
while(y++ <= y2)
{
*buffer = (uInt16) myFB.myDefPalette[color];
buffer += myPitch;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, uInt32 color)
{
// Fill the rectangle
SDL_Rect tmp;
tmp.x = x;
tmp.y = y;
tmp.w = w;
tmp.h = h;
SDL_FillRect(myTexture, &tmp, myFB.myDefPalette[color]);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::drawChar(const GUI::Font* font, uInt8 chr,
uInt32 tx, uInt32 ty, uInt32 color)
{
const FontDesc& desc = font->desc();
// If this character is not included in the font, use the default char.
if(chr < desc.firstchar || chr >= desc.firstchar + desc.size)
{
if (chr == ' ') return;
chr = desc.defaultchar;
}
chr -= desc.firstchar;
// Get the bounding box of the character
int bbw, bbh, bbx, bby;
if(!desc.bbx)
{
bbw = desc.fbbw;
bbh = desc.fbbh;
bbx = desc.fbbx;
bby = desc.fbby;
}
else
{
bbw = desc.bbx[chr].w;
bbh = desc.bbx[chr].h;
bbx = desc.bbx[chr].x;
bby = desc.bbx[chr].y;
}
const uInt16* tmp = desc.bits + (desc.offset ? desc.offset[chr] : (chr * desc.fbbh));
uInt16* buffer = (uInt16*) myTexture->pixels +
(ty + desc.ascent - bby - bbh) * myPitch +
tx + bbx;
for(int y = 0; y < bbh; y++)
{
const uInt16 ptr = *tmp++;
uInt16 mask = 0x8000;
for(int x = 0; x < bbw; x++, mask >>= 1)
if(ptr & mask)
buffer[x] = (uInt16) myFB.myDefPalette[color];
buffer += myPitch;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::drawBitmap(uInt32* bitmap, uInt32 tx, uInt32 ty,
uInt32 color, uInt32 h)
{
uInt16* buffer = (uInt16*) myTexture->pixels + ty * myPitch + tx;
for(uInt32 y = 0; y < h; ++y)
{
uInt32 mask = 0xF0000000;
for(uInt32 x = 0; x < 8; ++x, mask >>= 4)
if(bitmap[y] & mask)
buffer[x] = (uInt16) myFB.myDefPalette[color];
buffer += myPitch;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::drawPixels(uInt32* data, uInt32 tx, uInt32 ty, uInt32 numpixels)
{
uInt16* buffer = (uInt16*) myTexture->pixels + ty * myPitch + tx;
for(uInt32 i = 0; i < numpixels; ++i)
*buffer++ = (uInt16) data[i];
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::drawSurface(const FBSurface* surface, uInt32 tx, uInt32 ty)
{
const FBSurfaceGL* s = (const FBSurfaceGL*) surface;
SDL_Rect dstrect;
dstrect.x = tx;
dstrect.y = ty;
SDL_Rect srcrect;
srcrect.x = 0;
srcrect.y = 0;
srcrect.w = s->myWidth;
srcrect.h = s->myHeight;
SDL_BlitSurface(s->myTexture, &srcrect, myTexture, &dstrect);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::addDirtyRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h)
{
// OpenGL mode doesn't make use of dirty rectangles
// It's faster to just update the entire surface
mySurfaceIsDirty = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::getPos(uInt32& x, uInt32& y) const
{
x = myXOrig;
y = myYOrig;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::setPos(uInt32 x, uInt32 y)
{
if(myXOrig != x || myYOrig != y)
{
myXOrig = x;
myYOrig = y;
updateCoords();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::setWidth(uInt32 w)
{
// This method can't be used with 'scaled' surface (aka TIA surfaces)
// That shouldn't really matter, though, as all the UI stuff isn't scaled,
// and it's the only thing that uses it
if(myWidth != w)
{
myWidth = w;
myTexCoordW = (GLfloat) myWidth / myTexWidth;
updateCoords();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::setHeight(uInt32 h)
{
// This method can't be used with 'scaled' surface (aka TIA surfaces)
// That shouldn't really matter, though, as all the UI stuff isn't scaled,
// and it's the only thing that uses it
if(myHeight != h)
{
myHeight = h;
myTexCoordH = (GLfloat) myHeight / myTexHeight;
updateCoords();
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::translateCoords(Int32& x, Int32& y) const
{
x -= myXOrig;
y -= myYOrig;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::update()
{
if(mySurfaceIsDirty)
{
// Texturemap complete texture to surface so we have free scaling
// and antialiasing
p_glActiveTexture(GL_TEXTURE0);
p_glBindTexture(GL_TEXTURE_2D, myTexID);
p_glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, myTexWidth, myTexHeight,
#if defined(GL_BGRA) && defined(GL_UNSIGNED_SHORT_1_5_5_5_REV)
GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV,
#else
GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1,
#endif
myTexture->pixels);
p_glEnableClientState(GL_VERTEX_ARRAY);
p_glEnableClientState(GL_TEXTURE_COORD_ARRAY);
if(myFB.myVBOAvailable)
{
p_glBindBuffer(GL_ARRAY_BUFFER, myVBOID);
p_glVertexPointer(2, GL_FLOAT, 0, (const GLvoid*)0);
p_glTexCoordPointer(2, GL_FLOAT, 0, (const GLvoid*)(8*sizeof(GLfloat)));
}
else
{
p_glVertexPointer(2, GL_FLOAT, 0, myCoord);
p_glTexCoordPointer(2, GL_FLOAT, 0, myCoord+8);
}
p_glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
p_glDisableClientState(GL_VERTEX_ARRAY);
p_glDisableClientState(GL_TEXTURE_COORD_ARRAY);
mySurfaceIsDirty = false;
// Let postFrameUpdate() know that a change has been made
myFB.myDirtyFlag = true;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::free()
{
p_glDeleteTextures(1, &myTexID);
if(myFB.myVBOAvailable)
p_glDeleteBuffers(1, &myVBOID);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::reload()
{
// This does a 'soft' reset of the surface
// It seems that on some system (notably, OSX), creating a new SDL window
// destroys the GL context, requiring a reload of all textures
// However, destroying the entire FBSurfaceGL object is wasteful, since
// it will also regenerate SDL software surfaces (which are not required
// to be regenerated)
// Basically, all that needs to be done is to re-call glTexImage2D with a
// new texture ID, so that's what we do here
p_glActiveTexture(GL_TEXTURE0);
p_glEnable(GL_TEXTURE_2D);
p_glGenTextures(1, &myTexID);
p_glBindTexture(GL_TEXTURE_2D, myTexID);
p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Finally, create the texture in the most optimal format
p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
myTexWidth, myTexHeight, 0,
#if defined(GL_BGRA) && defined(GL_UNSIGNED_SHORT_1_5_5_5_REV)
GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV,
#else
GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1,
#endif
myTexture->pixels);
// Cache vertex and texture coordinates using vertex buffer object
if(myFB.myVBOAvailable)
{
p_glGenBuffers(1, &myVBOID);
p_glBindBuffer(GL_ARRAY_BUFFER, myVBOID);
p_glBufferData(GL_ARRAY_BUFFER, 16*sizeof(GLfloat), myCoord, GL_STATIC_DRAW);
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::setFilter(const string& name)
{
// We only do GL_NEAREST or GL_LINEAR for now
GLint filter = GL_NEAREST;
if(name == "linear")
filter = GL_LINEAR;
p_glBindTexture(GL_TEXTURE_2D, myTexID);
p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
// The filtering has changed, so redraw the entire screen
mySurfaceIsDirty = true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FBSurfaceGL::updateCoords()
{
// Vertex coordinates
// Upper left (x,y)
myCoord[0] = (GLfloat)myXOrig;
myCoord[1] = (GLfloat)myYOrig;
// Upper right (x+w,y)
myCoord[2] = (GLfloat)(myXOrig + myWidth);
myCoord[3] = (GLfloat)myYOrig;
// Lower left (x,y+h)
myCoord[4] = (GLfloat)myXOrig;
myCoord[5] = (GLfloat)(myYOrig + myHeight);
// Lower right (x+w,y+h)
myCoord[6] = (GLfloat)(myXOrig + myWidth);
myCoord[7] = (GLfloat)(myYOrig + myHeight);
// Texture coordinates
// Upper left (x,y)
myCoord[8] = 0.0f;
myCoord[9] = 0.0f;
// Upper right (x+w,y)
myCoord[10] = myTexCoordW;
myCoord[11] = 0.0f;
// Lower left (x,y+h)
myCoord[12] = 0.0f;
myCoord[13] = myTexCoordH;
// Lower right (x+w,y+h)
myCoord[14] = myTexCoordW;
myCoord[15] = myTexCoordH;
// Cache vertex and texture coordinates using vertex buffer object
if(myFB.myVBOAvailable)
{
p_glBindBuffer(GL_ARRAY_BUFFER, myVBOID);
p_glBufferData(GL_ARRAY_BUFFER, 16*sizeof(GLfloat), myCoord, GL_STATIC_DRAW);
}
p_gl.PixelStorei(GL_PACK_ALIGNMENT, 1);
p_gl.ReadPixels(image.x(), row, image.width(), 1, GL_RGB, GL_UNSIGNED_BYTE, data);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -28,10 +28,18 @@
class OSystem;
class FBSurfaceGL;
class FBSurfaceTIA;
class TIA;
#include "bspf.hxx"
#include "FrameBuffer.hxx"
// Make sure we have access to the most common pixel format
// (it isn't available in certain versions of OpenGL ES
#if defined(GL_BGRA) && defined(GL_UNSIGNED_SHORT_1_5_5_5_REV)
#define HAVE_GL_BGRA
#endif
/**
This class implements an SDL OpenGL framebuffer.
@ -41,6 +49,7 @@ class FBSurfaceGL;
class FrameBufferGL : public FrameBuffer
{
friend class FBSurfaceGL;
friend class FBSurfaceTIA;
public:
/**
@ -180,15 +189,18 @@ class FrameBufferGL : public FrameBuffer
};
bool loadFuncs(GLFunctionality functionality);
/**
Enable/disable texture effect.
*/
void enableTexture(bool enable);
static uInt32 power_of_two(uInt32 input)
{
uInt32 value = 1;
while( value < input )
value <<= 1;
return value;
}
private:
// The lower-most base surface (will always be a TIA surface,
// since Dialog surfaces are allocated by the Dialog class directly).
FBSurfaceGL* myTiaSurface;
FBSurfaceTIA* myTiaSurface;
// Used by mapRGB (when palettes are created)
SDL_PixelFormat myPixelFormat;
@ -205,9 +217,6 @@ class FrameBufferGL : public FrameBuffer
// Indicates that the texture has been modified, and should be redrawn
bool myDirtyFlag;
// Indicates whether or not the phosphor filter is enabled
bool myUseGLPhosphor;
// Indicates if the OpenGL library has been properly loaded
static bool myLibraryLoaded;
@ -216,72 +225,45 @@ class FrameBufferGL : public FrameBuffer
// Indicates whether Vertex/Frame Buffer Object functions were properly loaded
static bool myVBOAvailable, myFBOAvailable;
};
/**
A surface suitable for OpenGL rendering mode.
@author Stephen Anthony
@version $Id$
*/
class FBSurfaceGL : public FBSurface
{
friend class FrameBufferGL;
public:
FBSurfaceGL(FrameBufferGL& buffer,
uInt32 baseWidth, uInt32 baseHeight,
uInt32 scaleWidth, uInt32 scaleHeight,
bool allowFiltering);
virtual ~FBSurfaceGL();
void hLine(uInt32 x, uInt32 y, uInt32 x2, uInt32 color);
void vLine(uInt32 x, uInt32 y, uInt32 y2, uInt32 color);
void fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h, uInt32 color);
void drawChar(const GUI::Font* font, uInt8 c, uInt32 x, uInt32 y, uInt32 color);
void drawBitmap(uInt32* bitmap, uInt32 x, uInt32 y, uInt32 color, uInt32 h = 8);
void drawPixels(uInt32* data, uInt32 x, uInt32 y, uInt32 numpixels);
void drawSurface(const FBSurface* surface, uInt32 x, uInt32 y);
void addDirtyRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h);
void getPos(uInt32& x, uInt32& y) const;
void setPos(uInt32 x, uInt32 y);
uInt32 getWidth() const { return myWidth; }
uInt32 getHeight() const { return myHeight; }
void setWidth(uInt32 w);
void setHeight(uInt32 h);
void translateCoords(Int32& x, Int32& y) const;
void update();
void free();
void reload();
private:
void setFilter(const string& name);
void updateCoords();
void* pixels() const { return myTexture->pixels; }
uInt32 pitch() const { return myPitch; }
static uInt32 power_of_two(uInt32 input)
{
uInt32 value = 1;
while( value < input )
value <<= 1;
return value;
}
private:
FrameBufferGL& myFB;
SDL_Surface* myTexture;
GLuint myTexID, myVBOID;
GLsizei myTexWidth;
GLsizei myTexHeight;
GLuint myXOrig, myYOrig, myWidth, myHeight;
GLfloat myTexCoordW, myTexCoordH;
GLfloat myCoord[16];
bool mySurfaceIsDirty;
uInt32 myPitch;
// Structure containing dynamically-loaded OpenGL function pointers
#define OGL_DECLARE(NAME,RET,FUNC,PARAMS) RET (APIENTRY* NAME) PARAMS
typedef struct {
OGL_DECLARE(Clear,void,glClear,(GLbitfield));
OGL_DECLARE(Enable,void,glEnable,(GLenum));
OGL_DECLARE(Disable,void,glDisable,(GLenum));
OGL_DECLARE(PushAttrib,void,glPushAttrib,(GLbitfield));
OGL_DECLARE(GetString,const GLubyte*,glGetString,(GLenum));
OGL_DECLARE(Hint,void,glHint,(GLenum, GLenum));
OGL_DECLARE(ShadeModel,void,glShadeModel,(GLenum));
OGL_DECLARE(MatrixMode,void,glMatrixMode,(GLenum));
OGL_DECLARE(Ortho,void,glOrtho,(GLdouble, GLdouble, GLdouble, GLdouble, GLdouble, GLdouble));
OGL_DECLARE(Viewport,void,glViewport,(GLint, GLint, GLsizei, GLsizei));
OGL_DECLARE(LoadIdentity,void,glLoadIdentity,(void));
OGL_DECLARE(EnableClientState,void,glEnableClientState,(GLenum));
OGL_DECLARE(DisableClientState,void,glDisableClientState,(GLenum));
OGL_DECLARE(VertexPointer,void,glVertexPointer,(GLint,GLenum,GLsizei,const GLvoid*));
OGL_DECLARE(TexCoordPointer,void,glTexCoordPointer,(GLint,GLenum,GLsizei,const GLvoid*));
OGL_DECLARE(DrawArrays,void,glDrawArrays,(GLenum,GLint,GLsizei));
OGL_DECLARE(ReadPixels,void,glReadPixels,(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, GLvoid*));
OGL_DECLARE(PixelStorei,void,glPixelStorei,(GLenum, GLint));
OGL_DECLARE(TexEnvf,void,glTexEnvf,(GLenum, GLenum, GLfloat));
OGL_DECLARE(GenTextures,void,glGenTextures,(GLsizei, GLuint*));
OGL_DECLARE(DeleteTextures,void,glDeleteTextures,(GLsizei, const GLuint*));
OGL_DECLARE(ActiveTexture,void,glActiveTexture,(GLenum));
OGL_DECLARE(BindTexture,void,glBindTexture,(GLenum, GLuint));
OGL_DECLARE(TexImage2D,void,glTexImage2D,(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*));
OGL_DECLARE(TexSubImage2D,void,glTexSubImage2D,(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const GLvoid*));
OGL_DECLARE(TexParameteri,void,glTexParameteri,(GLenum, GLenum, GLint));
OGL_DECLARE(GetError,GLenum,glGetError,(void));
OGL_DECLARE(Color4f,void,glColor4f,(GLfloat,GLfloat,GLfloat,GLfloat));
OGL_DECLARE(BlendFunc,void,glBlendFunc,(GLenum,GLenum));
OGL_DECLARE(GenBuffers,void,glGenBuffers,(GLsizei,GLuint*));
OGL_DECLARE(BindBuffer,void,glBindBuffer,(GLenum,GLuint));
OGL_DECLARE(BufferData,void,glBufferData,(GLenum,GLsizei,const void*,GLenum));
OGL_DECLARE(DeleteBuffers,void,glDeleteBuffers,(GLsizei, const GLuint*));
} GLpointers;
GLpointers p_gl;
};
#endif // DISPLAY_OPENGL

View File

@ -6,6 +6,8 @@ MODULE_OBJS := \
src/common/SoundSDL.o \
src/common/FrameBufferSoft.o \
src/common/FrameBufferGL.o \
src/common/FBSurfaceGL.o \
src/common/FBSurfaceTIA.o \
src/common/PNGLibrary.o \
src/common/RectList.o \
src/common/Snapshot.o

View File

@ -648,7 +648,7 @@ class FBSurface
@param x2 The second x coordinate
@param color The color of the line
*/
virtual void hLine(uInt32 x, uInt32 y, uInt32 x2, uInt32 color) = 0;
virtual void hLine(uInt32 x, uInt32 y, uInt32 x2, uInt32 color) { }
/**
This method should be called to draw a vertical line.
@ -658,7 +658,7 @@ class FBSurface
@param y2 The second y coordinate
@param color The color of the line
*/
virtual void vLine(uInt32 x, uInt32 y, uInt32 y2, uInt32 color) = 0;
virtual void vLine(uInt32 x, uInt32 y, uInt32 y2, uInt32 color) { }
/**
This method should be called to draw a filled rectangle.
@ -670,7 +670,7 @@ class FBSurface
@param color
*/
virtual void fillRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h,
uInt32 color) = 0;
uInt32 color) { }
/**
This method should be called to draw the specified character.
@ -682,7 +682,7 @@ class FBSurface
@param color The color of the character
*/
virtual void drawChar(const GUI::Font* font, uInt8 c, uInt32 x, uInt32 y,
uInt32 color) = 0;
uInt32 color) { }
/**
This method should be called to draw the bitmap image.
@ -694,7 +694,7 @@ class FBSurface
@param h The height of the data image
*/
virtual void drawBitmap(uInt32* bitmap, uInt32 x, uInt32 y, uInt32 color,
uInt32 h = 8) = 0;
uInt32 h = 8) { }
/**
This method should be called to convert and copy a given row of pixel
@ -705,7 +705,7 @@ class FBSurface
@param row The row of the surface the data should be placed in
@param rowbytes The number of bytes in row of 'data'
*/
virtual void drawPixels(uInt32* data, uInt32 x, uInt32 y, uInt32 numpixels) = 0;
virtual void drawPixels(uInt32* data, uInt32 x, uInt32 y, uInt32 numpixels) { }
/**
This method should be called copy the contents of the given
@ -715,7 +715,7 @@ class FBSurface
@param x The x coordinate
@param y The y coordinate
*/
virtual void drawSurface(const FBSurface* surface, uInt32 x, uInt32 y) = 0;
virtual void drawSurface(const FBSurface* surface, uInt32 x, uInt32 y) { }
/**
This method should be called to add a dirty rectangle
@ -726,33 +726,33 @@ class FBSurface
@param w The width of the area
@param h The height of the area
*/
virtual void addDirtyRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h) = 0;
virtual void addDirtyRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h) { }
/**
This method answers the current position of the surface.
*/
virtual void getPos(uInt32& x, uInt32& y) const = 0;
virtual void getPos(uInt32& x, uInt32& y) const { }
/**
This method should be called to set the position of the surface.
*/
virtual void setPos(uInt32 x, uInt32 y) = 0;
virtual void setPos(uInt32 x, uInt32 y) { }
/**
This method answers the current dimensions of the surface.
*/
virtual uInt32 getWidth() const = 0;
virtual uInt32 getHeight() const = 0;
virtual uInt32 getWidth() const { return 0; }
virtual uInt32 getHeight() const { return 0; }
/**
This method sets the width of the drawable area of the surface.
*/
virtual void setWidth(uInt32 w) = 0;
virtual void setWidth(uInt32 w) { }
/**
This method sets the width of the drawable area of the surface.
*/
virtual void setHeight(uInt32 h) = 0;
virtual void setHeight(uInt32 h) { }
/**
This method should be called to translate the given coordinates
@ -761,24 +761,24 @@ class FBSurface
@param x X coordinate to translate
@param y Y coordinate to translate
*/
virtual void translateCoords(Int32& x, Int32& y) const = 0;
virtual void translateCoords(Int32& x, Int32& y) const { }
/**
This method should be called to draw the surface to the screen.
*/
virtual void update() = 0;
virtual void update() { }
/**
This method should be called to free any resources being used by
the surface.
*/
virtual void free() = 0;
virtual void free() { }
/**
This method should be called to reload the surface data/state.
It will normally be called after free().
*/
virtual void reload() = 0;
virtual void reload() { }
/**
This method should be called to draw a rectangular box with sides
@ -791,8 +791,8 @@ class FBSurface
@param colorA Lighter color for outside line.
@param colorB Darker color for inside line.
*/
void box(uInt32 x, uInt32 y, uInt32 w, uInt32 h,
uInt32 colorA, uInt32 colorB);
virtual void box(uInt32 x, uInt32 y, uInt32 w, uInt32 h,
uInt32 colorA, uInt32 colorB);
/**
This method should be called to draw a framed rectangle.
@ -804,8 +804,8 @@ class FBSurface
@param h The height of the area
@param color The color of the surrounding frame
*/
void frameRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h,
uInt32 color, FrameStyle style = kSolidLine);
virtual void frameRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h,
uInt32 color, FrameStyle style = kSolidLine);
/**
This method should be called to draw the specified string.
@ -821,9 +821,10 @@ class FBSurface
@param deltax
@param useEllipsis Whether to use '...' when the string is too long
*/
void drawString(const GUI::Font* font, const string& str, int x, int y, int w,
uInt32 color, TextAlignment align = kTextAlignLeft,
int deltax = 0, bool useEllipsis = true);
virtual void drawString(
const GUI::Font* font, const string& str, int x, int y, int w,
uInt32 color, TextAlignment align = kTextAlignLeft,
int deltax = 0, bool useEllipsis = true);
};
#endif