2013-04-05 06:13:26 +00:00
|
|
|
#ifndef __LINUX__
|
|
|
|
# include <windows.h>
|
|
|
|
#else
|
|
|
|
# include "winlnxdefs.h"
|
|
|
|
#endif // __LINUX__
|
2013-06-01 13:10:30 +00:00
|
|
|
#include <assert.h>
|
2013-04-05 06:13:26 +00:00
|
|
|
#include "OpenGL.h"
|
|
|
|
#include "FrameBuffer.h"
|
2013-06-01 13:10:30 +00:00
|
|
|
#include "DepthBuffer.h"
|
2013-04-05 06:13:26 +00:00
|
|
|
#include "RSP.h"
|
|
|
|
#include "RDP.h"
|
2013-06-29 11:52:57 +00:00
|
|
|
#include "gDP.h"
|
2013-08-10 11:12:17 +00:00
|
|
|
#include "VI.h"
|
2013-04-05 06:13:26 +00:00
|
|
|
#include "Textures.h"
|
|
|
|
#include "Combiner.h"
|
|
|
|
#include "Types.h"
|
2013-06-01 13:10:30 +00:00
|
|
|
#include "Debug.h"
|
|
|
|
|
2013-08-31 15:06:24 +00:00
|
|
|
bool g_bCopyToRDRAM = false;
|
2013-04-05 06:13:26 +00:00
|
|
|
FrameBufferInfo frameBuffer;
|
|
|
|
|
2013-08-10 11:12:17 +00:00
|
|
|
static GLuint g_cur_frame_fbo = 0;
|
|
|
|
static GLuint g_cur_frame_tex = 0;
|
|
|
|
|
2013-04-05 06:13:26 +00:00
|
|
|
void FrameBuffer_Init()
|
|
|
|
{
|
|
|
|
frameBuffer.current = NULL;
|
|
|
|
frameBuffer.top = NULL;
|
|
|
|
frameBuffer.bottom = NULL;
|
|
|
|
frameBuffer.numBuffers = 0;
|
2013-06-01 13:10:30 +00:00
|
|
|
frameBuffer.drawBuffer = GL_BACK;
|
2013-08-10 11:12:17 +00:00
|
|
|
|
|
|
|
|
|
|
|
// generate a framebuffer
|
|
|
|
ogl_glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
|
|
|
ogl_glGenFramebuffers(1, &g_cur_frame_fbo);
|
|
|
|
ogl_glBindFramebuffer(GL_DRAW_FRAMEBUFFER, g_cur_frame_fbo);
|
|
|
|
|
|
|
|
glGenTextures(1, &g_cur_frame_tex);
|
|
|
|
glBindTexture(GL_TEXTURE_2D, g_cur_frame_tex);
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1024, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
|
|
|
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
|
|
|
|
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
ogl_glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, g_cur_frame_tex, 0);
|
|
|
|
// check if everything is OK
|
|
|
|
assert(checkFBO());
|
|
|
|
ogl_glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
2013-04-05 06:13:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FrameBuffer_RemoveBottom()
|
|
|
|
{
|
|
|
|
FrameBuffer *newBottom = frameBuffer.bottom->higher;
|
|
|
|
|
|
|
|
TextureCache_Remove( frameBuffer.bottom->texture );
|
2013-06-01 13:10:30 +00:00
|
|
|
if (frameBuffer.bottom->fbo != 0)
|
|
|
|
ogl_glDeleteFramebuffers(1, &frameBuffer.bottom->fbo);
|
2013-04-05 06:13:26 +00:00
|
|
|
|
|
|
|
if (frameBuffer.bottom == frameBuffer.top)
|
|
|
|
frameBuffer.top = NULL;
|
|
|
|
|
|
|
|
free( frameBuffer.bottom );
|
|
|
|
|
|
|
|
frameBuffer.bottom = newBottom;
|
|
|
|
|
|
|
|
if (frameBuffer.bottom != NULL)
|
|
|
|
frameBuffer.bottom->lower = NULL;
|
|
|
|
|
|
|
|
frameBuffer.numBuffers--;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FrameBuffer_Remove( FrameBuffer *buffer )
|
|
|
|
{
|
|
|
|
if ((buffer == frameBuffer.bottom) &&
|
|
|
|
(buffer == frameBuffer.top))
|
|
|
|
{
|
|
|
|
frameBuffer.top = NULL;
|
|
|
|
frameBuffer.bottom = NULL;
|
|
|
|
}
|
|
|
|
else if (buffer == frameBuffer.bottom)
|
|
|
|
{
|
|
|
|
frameBuffer.bottom = buffer->higher;
|
|
|
|
|
|
|
|
if (frameBuffer.bottom)
|
|
|
|
frameBuffer.bottom->lower = NULL;
|
|
|
|
}
|
|
|
|
else if (buffer == frameBuffer.top)
|
|
|
|
{
|
|
|
|
frameBuffer.top = buffer->lower;
|
|
|
|
|
|
|
|
if (frameBuffer.top)
|
|
|
|
frameBuffer.top->higher = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
buffer->higher->lower = buffer->lower;
|
|
|
|
buffer->lower->higher = buffer->higher;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (buffer->texture)
|
|
|
|
TextureCache_Remove( buffer->texture );
|
2013-06-01 13:10:30 +00:00
|
|
|
if (buffer->fbo != 0)
|
|
|
|
ogl_glDeleteFramebuffers(1, &buffer->fbo);
|
2013-04-05 06:13:26 +00:00
|
|
|
|
|
|
|
free( buffer );
|
|
|
|
|
|
|
|
frameBuffer.numBuffers--;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FrameBuffer_RemoveBuffer( u32 address )
|
|
|
|
{
|
|
|
|
FrameBuffer *current = frameBuffer.bottom;
|
|
|
|
|
|
|
|
while (current != NULL)
|
|
|
|
{
|
|
|
|
if (current->startAddress == address)
|
|
|
|
{
|
2013-08-10 11:10:44 +00:00
|
|
|
//current->texture = NULL;
|
2013-04-05 06:13:26 +00:00
|
|
|
FrameBuffer_Remove( current );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
current = current->higher;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FrameBuffer *FrameBuffer_AddTop()
|
|
|
|
{
|
|
|
|
FrameBuffer *newtop = (FrameBuffer*)malloc( sizeof( FrameBuffer ) );
|
|
|
|
|
|
|
|
newtop->texture = TextureCache_AddTop();
|
2013-06-01 13:10:30 +00:00
|
|
|
newtop->fbo = 0;
|
2013-04-05 06:13:26 +00:00
|
|
|
|
|
|
|
newtop->lower = frameBuffer.top;
|
|
|
|
newtop->higher = NULL;
|
|
|
|
|
|
|
|
if (frameBuffer.top)
|
|
|
|
frameBuffer.top->higher = newtop;
|
|
|
|
|
|
|
|
if (!frameBuffer.bottom)
|
|
|
|
frameBuffer.bottom = newtop;
|
|
|
|
|
|
|
|
frameBuffer.top = newtop;
|
|
|
|
|
|
|
|
frameBuffer.numBuffers++;
|
|
|
|
|
|
|
|
return newtop;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FrameBuffer_MoveToTop( FrameBuffer *newtop )
|
|
|
|
{
|
|
|
|
if (newtop == frameBuffer.top)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (newtop == frameBuffer.bottom)
|
|
|
|
{
|
|
|
|
frameBuffer.bottom = newtop->higher;
|
|
|
|
frameBuffer.bottom->lower = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
newtop->higher->lower = newtop->lower;
|
|
|
|
newtop->lower->higher = newtop->higher;
|
|
|
|
}
|
|
|
|
|
|
|
|
newtop->higher = NULL;
|
|
|
|
newtop->lower = frameBuffer.top;
|
|
|
|
frameBuffer.top->higher = newtop;
|
|
|
|
frameBuffer.top = newtop;
|
|
|
|
|
|
|
|
TextureCache_MoveToTop( newtop->texture );
|
|
|
|
}
|
|
|
|
|
|
|
|
void FrameBuffer_Destroy()
|
|
|
|
{
|
|
|
|
while (frameBuffer.bottom)
|
|
|
|
FrameBuffer_RemoveBottom();
|
2013-08-10 11:12:17 +00:00
|
|
|
|
|
|
|
ogl_glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
|
|
|
glDeleteTextures(1, &g_cur_frame_tex);
|
|
|
|
ogl_glDeleteFramebuffers(1, &g_cur_frame_fbo);
|
2013-04-05 06:13:26 +00:00
|
|
|
}
|
|
|
|
|
2013-08-31 15:06:24 +00:00
|
|
|
void FrameBuffer_CopyAuxBufferToRDRAM( u32 address );
|
2013-06-11 17:20:10 +00:00
|
|
|
void FrameBuffer_SaveBuffer( u32 address, u16 format, u16 size, u16 width, u16 height )
|
2013-04-05 06:13:26 +00:00
|
|
|
{
|
2013-06-01 13:10:30 +00:00
|
|
|
frameBuffer.drawBuffer = GL_DRAW_FRAMEBUFFER;
|
2013-06-02 15:20:44 +00:00
|
|
|
FrameBuffer *current = frameBuffer.top;
|
2013-08-10 11:10:44 +00:00
|
|
|
if (current != NULL && gDP.colorImage.height > 1) {
|
2013-08-31 15:06:24 +00:00
|
|
|
current->endAddress = current->startAddress + (((current->width * gDP.colorImage.height) << current->size >> 1) - 1);
|
|
|
|
if (current->startAddress == 0x13ba50 || current->startAddress == 0x264430) { // HACK ALERT: Dirty hack for Mario Tennis score board
|
|
|
|
FrameBuffer_CopyAuxBufferToRDRAM(current->startAddress);
|
|
|
|
FrameBuffer_Remove( current );
|
|
|
|
current = NULL;
|
|
|
|
} else if (!g_bCopyToRDRAM && !current->cleared)
|
2013-08-10 11:10:44 +00:00
|
|
|
gDPFillRDRAM(current->startAddress, 0, 0, current->width, gDP.colorImage.height, current->width, current->size, frameBuffer.top->fillcolor);
|
|
|
|
}
|
|
|
|
|
2013-04-05 06:13:26 +00:00
|
|
|
// Search through saved frame buffers
|
|
|
|
while (current != NULL)
|
|
|
|
{
|
2013-06-01 13:10:30 +00:00
|
|
|
if ((current->startAddress <= address) &&
|
|
|
|
(current->endAddress >= address))
|
2013-04-05 06:13:26 +00:00
|
|
|
{
|
2013-06-02 15:20:44 +00:00
|
|
|
if ((current->startAddress != address) ||
|
|
|
|
(current->width != width) ||
|
|
|
|
//(current->height != height) ||
|
2013-06-29 11:51:06 +00:00
|
|
|
//(current->size != size) || // TODO FIX ME
|
2013-06-01 13:10:30 +00:00
|
|
|
(current->scaleX != OGL.scaleX) ||
|
2013-04-05 06:13:26 +00:00
|
|
|
(current->scaleY != OGL.scaleY))
|
|
|
|
{
|
|
|
|
FrameBuffer_Remove( current );
|
2013-06-04 16:05:09 +00:00
|
|
|
current = NULL;
|
2013-04-05 06:13:26 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
FrameBuffer_MoveToTop( current );
|
2013-06-04 16:05:09 +00:00
|
|
|
ogl_glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current->fbo);
|
2013-06-29 11:51:06 +00:00
|
|
|
if (current->size != size) {
|
|
|
|
f32 fillColor[4];
|
|
|
|
gDPGetFillColor(fillColor);
|
|
|
|
OGL_ClearColorBuffer(fillColor);
|
|
|
|
current->size = size;
|
|
|
|
current->texture->format = format;
|
|
|
|
current->texture->size = size;
|
|
|
|
}
|
2013-06-04 16:05:09 +00:00
|
|
|
break;
|
2013-04-05 06:13:26 +00:00
|
|
|
}
|
|
|
|
current = current->lower;
|
|
|
|
}
|
|
|
|
|
2013-06-04 16:05:09 +00:00
|
|
|
if (current == NULL) {
|
|
|
|
// Wasn't found, create a new one
|
|
|
|
current = FrameBuffer_AddTop();
|
|
|
|
|
|
|
|
current->startAddress = address;
|
|
|
|
current->endAddress = address + ((width * height << size >> 1) - 1);
|
|
|
|
current->width = width;
|
|
|
|
current->height = height;
|
|
|
|
current->size = size;
|
|
|
|
current->scaleX = OGL.scaleX;
|
|
|
|
current->scaleY = OGL.scaleY;
|
2013-08-10 11:10:44 +00:00
|
|
|
current->fillcolor = 0;
|
2013-06-04 16:05:09 +00:00
|
|
|
|
|
|
|
current->texture->width = (u32)(current->width * OGL.scaleX);
|
|
|
|
current->texture->height = (u32)(current->height * OGL.scaleY);
|
2013-06-11 17:20:10 +00:00
|
|
|
current->texture->format = format;
|
|
|
|
current->texture->size = size;
|
2013-06-04 16:05:09 +00:00
|
|
|
current->texture->clampS = 1;
|
|
|
|
current->texture->clampT = 1;
|
|
|
|
current->texture->address = current->startAddress;
|
|
|
|
current->texture->clampWidth = current->width;
|
|
|
|
current->texture->clampHeight = current->height;
|
|
|
|
current->texture->frameBufferTexture = TRUE;
|
|
|
|
current->texture->maskS = 0;
|
|
|
|
current->texture->maskT = 0;
|
|
|
|
current->texture->mirrorS = 0;
|
|
|
|
current->texture->mirrorT = 0;
|
|
|
|
current->texture->realWidth = (u32)pow2( current->texture->width );
|
|
|
|
current->texture->realHeight = (u32)pow2( current->texture->height );
|
|
|
|
current->texture->textureBytes = current->texture->realWidth * current->texture->realHeight * 4;
|
|
|
|
cache.cachedBytes += current->texture->textureBytes;
|
|
|
|
|
|
|
|
glBindTexture( GL_TEXTURE_2D, current->texture->glName );
|
2013-06-11 17:20:10 +00:00
|
|
|
if (size > G_IM_SIZ_8b)
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, current->texture->realWidth, current->texture->realHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
|
|
|
else
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, current->texture->realWidth, current->texture->realHeight, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
|
2013-06-04 16:05:09 +00:00
|
|
|
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
|
|
|
|
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
|
|
|
|
ogl_glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
|
|
|
ogl_glGenFramebuffers(1, ¤t->fbo);
|
|
|
|
ogl_glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current->fbo);
|
|
|
|
ogl_glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, current->texture->glName, 0);
|
|
|
|
}
|
2013-06-01 13:10:30 +00:00
|
|
|
|
|
|
|
if (depthBuffer.top != NULL && depthBuffer.top->renderbuf > 0) {
|
|
|
|
ogl_glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer.top->renderbuf);
|
|
|
|
ogl_glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer.top->renderbuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
GLuint attachments[2] = { GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT };
|
|
|
|
ogl_glDrawBuffers(2, attachments, current->texture->glName);
|
|
|
|
assert(checkFBO());
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "FrameBuffer_SaveBuffer( 0x%08X ); depth buffer is 0x%08X\n",
|
|
|
|
address, (depthBuffer.top != NULL && depthBuffer.top->renderbuf > 0) ? depthBuffer.top->address : 0
|
|
|
|
);
|
|
|
|
#endif
|
2013-04-05 06:13:26 +00:00
|
|
|
*(u32*)&RDRAM[current->startAddress] = current->startAddress;
|
|
|
|
|
2013-08-10 11:10:44 +00:00
|
|
|
current->cleared = false;
|
2013-04-05 06:13:26 +00:00
|
|
|
|
|
|
|
gSP.changed |= CHANGED_TEXTURE;
|
|
|
|
}
|
|
|
|
|
2013-06-01 13:13:04 +00:00
|
|
|
|
|
|
|
#if 1
|
|
|
|
void FrameBuffer_RenderBuffer( u32 address )
|
|
|
|
{
|
|
|
|
FrameBuffer *current = frameBuffer.top;
|
|
|
|
|
|
|
|
while (current != NULL)
|
|
|
|
{
|
|
|
|
if ((current->startAddress <= address) &&
|
|
|
|
(current->endAddress >= address))
|
|
|
|
{
|
|
|
|
ogl_glBindFramebuffer(GL_READ_FRAMEBUFFER, current->fbo);
|
|
|
|
ogl_glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
|
|
|
glDrawBuffer( GL_FRONT );
|
|
|
|
ogl_glBlitFramebuffer(
|
2013-06-02 15:20:44 +00:00
|
|
|
// 0, 0, current->texture->realWidth, current->texture->realHeight,
|
|
|
|
0, 0, OGL.width, OGL.height,
|
2013-06-01 13:13:04 +00:00
|
|
|
0, OGL.heightOffset, OGL.width, OGL.height+OGL.heightOffset,
|
|
|
|
GL_COLOR_BUFFER_BIT, GL_LINEAR
|
|
|
|
);
|
|
|
|
glDrawBuffer( GL_BACK );
|
|
|
|
ogl_glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer.top->fbo);
|
2013-06-02 15:20:44 +00:00
|
|
|
/*
|
|
|
|
current = current->lower;
|
|
|
|
while (current != NULL)
|
|
|
|
{
|
|
|
|
if ((current->startAddress <= address) &&
|
|
|
|
(current->endAddress >= address))
|
|
|
|
assert(false);
|
|
|
|
current = current->lower;
|
|
|
|
}
|
|
|
|
*/
|
2013-06-01 13:13:04 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
current = current->lower;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
|
2013-04-05 06:13:26 +00:00
|
|
|
void FrameBuffer_RenderBuffer( u32 address )
|
|
|
|
{
|
|
|
|
FrameBuffer *current = frameBuffer.top;
|
|
|
|
|
|
|
|
while (current != NULL)
|
|
|
|
{
|
|
|
|
if ((current->startAddress <= address) &&
|
|
|
|
(current->endAddress >= address))
|
|
|
|
{
|
2013-06-02 15:20:44 +00:00
|
|
|
/*
|
|
|
|
float fill_color[4] = {1.0f, 0.0f, 0.0f, 1.0f};
|
|
|
|
ogl_glBindFramebuffer(GL_DRAW_FRAMEBUFFER, current->fbo);
|
|
|
|
ogl_glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer.top->renderbuf);
|
|
|
|
ogl_glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer.top->renderbuf);
|
|
|
|
GLuint attachments[2] = { GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT };
|
|
|
|
ogl_glDrawBuffers(2, attachments, current->texture->glName);
|
|
|
|
assert(checkFBO());
|
|
|
|
OGL_ClearDepthBuffer();
|
|
|
|
OGL_ClearColorBuffer(fill_color);
|
|
|
|
ogl_glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer.top->fbo);
|
|
|
|
*/
|
|
|
|
|
2013-04-05 06:13:26 +00:00
|
|
|
glPushAttrib( GL_ENABLE_BIT | GL_VIEWPORT_BIT );
|
|
|
|
|
|
|
|
Combiner_BeginTextureUpdate();
|
|
|
|
TextureCache_ActivateTexture( 0, current->texture );
|
|
|
|
Combiner_SetCombine( EncodeCombineMode( 0, 0, 0, TEXEL0, 0, 0, 0, 1, 0, 0, 0, TEXEL0, 0, 0, 0, 1 ) );
|
|
|
|
/* if (OGL.ARB_multitexture)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < OGL.maxTextureUnits; i++)
|
|
|
|
{
|
|
|
|
glActiveTextureARB( GL_TEXTURE0_ARB + i );
|
|
|
|
glDisable( GL_TEXTURE_2D );
|
|
|
|
}
|
|
|
|
|
|
|
|
glActiveTextureARB( GL_TEXTURE0_ARB );
|
|
|
|
}
|
|
|
|
|
|
|
|
TextureCache_ActivateTexture( 0, current->texture );
|
|
|
|
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
|
|
|
|
glEnable( GL_TEXTURE_2D );*/
|
|
|
|
|
|
|
|
glDisable( GL_BLEND );
|
|
|
|
glDisable( GL_ALPHA_TEST );
|
|
|
|
glDisable( GL_DEPTH_TEST );
|
|
|
|
glDisable( GL_CULL_FACE );
|
|
|
|
glDisable( GL_POLYGON_OFFSET_FILL );
|
|
|
|
// glDisable( GL_REGISTER_COMBINERS_NV );
|
|
|
|
glDisable( GL_FOG );
|
|
|
|
|
|
|
|
glMatrixMode( GL_PROJECTION );
|
|
|
|
glLoadIdentity();
|
|
|
|
glOrtho( 0, OGL.width, 0, OGL.height, -1.0f, 1.0f );
|
|
|
|
glViewport( 0, OGL.heightOffset, OGL.width, OGL.height );
|
|
|
|
glDisable( GL_SCISSOR_TEST );
|
|
|
|
|
|
|
|
float u1, v1;
|
|
|
|
|
|
|
|
u1 = (float)current->texture->width / (float)current->texture->realWidth;
|
|
|
|
v1 = (float)current->texture->height / (float)current->texture->realHeight;
|
|
|
|
|
2013-06-01 13:10:30 +00:00
|
|
|
ogl_glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
2013-04-05 06:13:26 +00:00
|
|
|
glDrawBuffer( GL_FRONT );
|
|
|
|
glBegin(GL_QUADS);
|
|
|
|
glTexCoord2f( 0.0f, 0.0f );
|
2013-04-22 05:19:52 +00:00
|
|
|
glVertex2f( 0.0f, (GLfloat)(OGL.height - current->texture->height) );
|
2013-04-05 06:13:26 +00:00
|
|
|
|
|
|
|
glTexCoord2f( 0.0f, v1 );
|
2013-04-22 05:19:52 +00:00
|
|
|
glVertex2f( 0.0f, (GLfloat)OGL.height );
|
2013-04-05 06:13:26 +00:00
|
|
|
|
|
|
|
glTexCoord2f( u1, v1 );
|
2013-04-22 05:19:52 +00:00
|
|
|
glVertex2f( current->texture->width, (GLfloat)OGL.height );
|
2013-04-05 06:13:26 +00:00
|
|
|
|
|
|
|
glTexCoord2f( u1, 0.0f );
|
2013-04-22 05:19:52 +00:00
|
|
|
glVertex2f( current->texture->width, (GLfloat)(OGL.height - current->texture->height) );
|
2013-04-05 06:13:26 +00:00
|
|
|
glEnd();
|
|
|
|
glDrawBuffer( GL_BACK );
|
2013-06-01 13:10:30 +00:00
|
|
|
ogl_glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer.top->fbo);
|
|
|
|
#ifdef DEBUG
|
|
|
|
DebugMsg( DEBUG_HIGH | DEBUG_HANDLED, "FrameBuffer_RenderBuffer( 0x%08X ); \n", address);
|
|
|
|
#endif
|
2013-04-05 06:13:26 +00:00
|
|
|
|
|
|
|
/* glEnable( GL_TEXTURE_2D );
|
|
|
|
glActiveTextureARB( GL_TEXTURE0_ARB );
|
|
|
|
glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );*/
|
2013-06-01 13:10:30 +00:00
|
|
|
glLoadIdentity();
|
2013-04-05 06:13:26 +00:00
|
|
|
glPopAttrib();
|
|
|
|
|
|
|
|
current->changed = FALSE;
|
|
|
|
|
|
|
|
gSP.changed |= CHANGED_TEXTURE | CHANGED_VIEWPORT;
|
|
|
|
gDP.changed |= CHANGED_COMBINE;
|
2013-06-01 13:10:30 +00:00
|
|
|
|
2013-04-05 06:13:26 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
current = current->lower;
|
|
|
|
}
|
|
|
|
}
|
2013-06-01 13:13:04 +00:00
|
|
|
#endif
|
2013-06-01 13:10:30 +00:00
|
|
|
|
2013-08-10 11:12:17 +00:00
|
|
|
struct RGBA {
|
|
|
|
u8 r, g, b, a;
|
|
|
|
};
|
|
|
|
|
|
|
|
void FrameBuffer_CopyToRDRAM( u32 address )
|
|
|
|
{
|
|
|
|
FrameBuffer *current = frameBuffer.top;
|
|
|
|
while (current != NULL)
|
|
|
|
{
|
|
|
|
if ((current->startAddress <= address) &&
|
|
|
|
(current->endAddress >= address))
|
|
|
|
{
|
|
|
|
ogl_glBindFramebuffer(GL_READ_FRAMEBUFFER, current->fbo);
|
|
|
|
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
|
|
|
ogl_glBindFramebuffer(GL_DRAW_FRAMEBUFFER, g_cur_frame_fbo);
|
|
|
|
GLuint attachment = GL_COLOR_ATTACHMENT0;
|
|
|
|
glDrawBuffers(1, &attachment);
|
|
|
|
ogl_glBlitFramebuffer(
|
|
|
|
0, 0, OGL.width, OGL.height,
|
|
|
|
0, 0, current->width, current->height,
|
|
|
|
GL_COLOR_BUFFER_BIT, GL_LINEAR
|
|
|
|
);
|
|
|
|
ogl_glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer.top->fbo);
|
|
|
|
|
|
|
|
char *pixelData = (char*)malloc( VI.width * VI.height * 4 );
|
|
|
|
if (*pixelData == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ogl_glBindFramebuffer(GL_READ_FRAMEBUFFER, g_cur_frame_fbo);
|
|
|
|
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
|
|
|
const u32 offset = (address - current->startAddress) / (VI.width<<current->size>>1);
|
|
|
|
glReadPixels( 0, offset, VI.width, VI.height, GL_RGBA, GL_UNSIGNED_BYTE, pixelData );
|
|
|
|
if (current->size == G_IM_SIZ_32b) {
|
|
|
|
u32 *ptr_dst = (u32*)(RDRAM + address);
|
|
|
|
u32 *ptr_src = (u32*)pixelData;
|
|
|
|
|
|
|
|
for (u32 y = 0; y < VI.height; ++y) {
|
|
|
|
for (u32 x = 0; x < VI.width; ++x)
|
|
|
|
ptr_dst[x + y*VI.width] = ptr_src[x + (VI.height - y - 1)*VI.width];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
u16 *ptr_dst = (u16*)(RDRAM + address);
|
|
|
|
u16 col;
|
|
|
|
RGBA * ptr_src = (RGBA*)pixelData;
|
|
|
|
|
|
|
|
for (u32 y = 0; y < VI.height; ++y) {
|
|
|
|
for (u32 x = 0; x < VI.width; ++x) {
|
|
|
|
const RGBA & c = ptr_src[x + (VI.height - y - 1)*VI.width];
|
|
|
|
ptr_dst[(x + y*VI.width)^1] = ((c.r>>3)<<11) | ((c.g>>3)<<6) | ((c.b>>3)<<1) | (c.a == 0 ? 0 : 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free( pixelData );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
current = current->lower;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-31 15:06:24 +00:00
|
|
|
static
|
|
|
|
void FrameBuffer_CopyAuxBufferToRDRAM( u32 address )
|
|
|
|
{
|
|
|
|
FrameBuffer *current = frameBuffer.top;
|
|
|
|
while (current != NULL)
|
|
|
|
{
|
|
|
|
if ((current->startAddress <= address) &&
|
|
|
|
(current->endAddress >= address))
|
|
|
|
{
|
|
|
|
ogl_glBindFramebuffer(GL_READ_FRAMEBUFFER, current->fbo);
|
|
|
|
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
|
|
|
ogl_glBindFramebuffer(GL_DRAW_FRAMEBUFFER, g_cur_frame_fbo);
|
|
|
|
GLuint attachment = GL_COLOR_ATTACHMENT0;
|
|
|
|
glDrawBuffers(1, &attachment);
|
|
|
|
const u32 width = current->width;
|
|
|
|
const u32 height = (current->endAddress - current->startAddress + 1) / (current->width<<current->size>>1);
|
|
|
|
ogl_glBlitFramebuffer(
|
|
|
|
0, (current->height - height)*OGL.scaleY, width*OGL.scaleX, current->height*OGL.scaleY,
|
|
|
|
0, 0, width, height,
|
|
|
|
GL_COLOR_BUFFER_BIT, GL_LINEAR
|
|
|
|
);
|
|
|
|
|
|
|
|
char *pixelData = (char*)malloc(width * height * 4);
|
|
|
|
if (*pixelData == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ogl_glBindFramebuffer(GL_READ_FRAMEBUFFER, g_cur_frame_fbo);
|
|
|
|
glReadBuffer(GL_COLOR_ATTACHMENT0);
|
|
|
|
glReadPixels( 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixelData );
|
|
|
|
if (current->size == G_IM_SIZ_32b) {
|
|
|
|
u32 *ptr_dst = (u32*)(RDRAM + address);
|
|
|
|
u32 *ptr_src = (u32*)pixelData;
|
|
|
|
|
|
|
|
for (u32 y = 0; y < height; ++y) {
|
|
|
|
for (u32 x = 0; x < width; ++x) {
|
|
|
|
const u32 c = ptr_src[x + (height - y - 1)*width];
|
|
|
|
if (c&0xFF > 0)
|
|
|
|
ptr_dst[x + y*width] = ptr_src[x + (height - y - 1)*width];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
u16 *ptr_dst = (u16*)(RDRAM + address);
|
|
|
|
u16 col;
|
|
|
|
RGBA * ptr_src = (RGBA*)pixelData;
|
|
|
|
|
|
|
|
for (u32 y = 0; y < height; ++y) {
|
|
|
|
for (u32 x = 0; x < width; ++x) {
|
|
|
|
const RGBA c = ptr_src[x + (height - y - 1)*width];
|
|
|
|
if (c.a > 0)
|
|
|
|
ptr_dst[(x + y*width)^1] = ((c.r>>3)<<11) | ((c.g>>3)<<6) | ((c.b>>3)<<1) | (c.a == 0 ? 0 : 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free( pixelData );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
current = current->lower;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-05 06:13:26 +00:00
|
|
|
FrameBuffer *FrameBuffer_FindBuffer( u32 address )
|
|
|
|
{
|
|
|
|
FrameBuffer *current = frameBuffer.top;
|
|
|
|
|
|
|
|
while (current)
|
|
|
|
{
|
|
|
|
if ((current->startAddress <= address) &&
|
|
|
|
(current->endAddress >= address))
|
|
|
|
return current;
|
|
|
|
current = current->lower;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FrameBuffer_ActivateBufferTexture( s16 t, FrameBuffer *buffer )
|
|
|
|
{
|
|
|
|
buffer->texture->scaleS = OGL.scaleX / (float)buffer->texture->realWidth;
|
|
|
|
buffer->texture->scaleT = OGL.scaleY / (float)buffer->texture->realHeight;
|
|
|
|
|
|
|
|
if (gSP.textureTile[t]->shifts > 10)
|
|
|
|
buffer->texture->shiftScaleS = (float)(1 << (16 - gSP.textureTile[t]->shifts));
|
|
|
|
else if (gSP.textureTile[t]->shifts > 0)
|
|
|
|
buffer->texture->shiftScaleS = 1.0f / (float)(1 << gSP.textureTile[t]->shifts);
|
|
|
|
else
|
|
|
|
buffer->texture->shiftScaleS = 1.0f;
|
|
|
|
|
|
|
|
if (gSP.textureTile[t]->shiftt > 10)
|
|
|
|
buffer->texture->shiftScaleT = (float)(1 << (16 - gSP.textureTile[t]->shiftt));
|
|
|
|
else if (gSP.textureTile[t]->shiftt > 0)
|
|
|
|
buffer->texture->shiftScaleT = 1.0f / (float)(1 << gSP.textureTile[t]->shiftt);
|
|
|
|
else
|
|
|
|
buffer->texture->shiftScaleT = 1.0f;
|
|
|
|
|
2013-06-15 13:46:48 +00:00
|
|
|
const u32 shift = gSP.textureTile[t]->imageAddress - buffer->startAddress;
|
2013-06-15 08:06:11 +00:00
|
|
|
const u32 factor = buffer->width << buffer->size >> 1;
|
2013-06-15 13:46:48 +00:00
|
|
|
if (gSP.textureTile[t]->loadType == LOADTYPE_TILE)
|
2013-04-05 06:13:26 +00:00
|
|
|
{
|
2013-06-29 11:52:57 +00:00
|
|
|
buffer->texture->offsetS = buffer->loadTile->uls;
|
|
|
|
buffer->texture->offsetT = (float)(buffer->height - (buffer->loadTile->ult + shift/factor));
|
2013-04-05 06:13:26 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-06-13 09:57:48 +00:00
|
|
|
buffer->texture->offsetS = (float)(shift % factor);
|
|
|
|
buffer->texture->offsetT = (float)(buffer->height - shift/factor);
|
2013-04-05 06:13:26 +00:00
|
|
|
}
|
|
|
|
|
2013-06-02 15:20:44 +00:00
|
|
|
// FrameBuffer_RenderBuffer(buffer->startAddress);
|
2013-04-05 06:13:26 +00:00
|
|
|
TextureCache_ActivateTexture( t, buffer->texture );
|
2013-06-11 17:20:10 +00:00
|
|
|
gDP.changed |= CHANGED_FB_TEXTURE;
|
2013-04-05 06:13:26 +00:00
|
|
|
}
|
2013-06-09 11:55:21 +00:00
|
|
|
|
|
|
|
void FrameBuffer_ActivateBufferTextureBG( s16 t, FrameBuffer *buffer )
|
|
|
|
{
|
|
|
|
buffer->texture->scaleS = OGL.scaleX / (float)buffer->texture->realWidth;
|
|
|
|
buffer->texture->scaleT = OGL.scaleY / (float)buffer->texture->realHeight;
|
|
|
|
|
|
|
|
buffer->texture->shiftScaleS = 1.0f;
|
|
|
|
buffer->texture->shiftScaleT = 1.0f;
|
|
|
|
|
|
|
|
buffer->texture->offsetS = gSP.bgImage.imageX;
|
|
|
|
buffer->texture->offsetT = (float)buffer->height - gSP.bgImage.imageY;
|
|
|
|
|
|
|
|
// FrameBuffer_RenderBuffer(buffer->startAddress);
|
|
|
|
TextureCache_ActivateTexture( t, buffer->texture );
|
2013-06-11 17:20:10 +00:00
|
|
|
gDP.changed |= CHANGED_FB_TEXTURE;
|
2013-06-09 11:55:21 +00:00
|
|
|
}
|