mirror of https://github.com/stella-emu/stella.git
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:
parent
b45d65fc31
commit
c2992f5097
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue