pcsx2/plugins/GSdx/GSTextureSW.cpp

203 lines
4.1 KiB
C++

/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSTextureSW.h"
GSTextureSW::GSTextureSW(int type, int width, int height)
: m_mapped(0)
{
m_size = GSVector2i(width, height);
m_type = type;
m_format = 0;
m_pitch = ((width << 2) + 31) & ~31;
m_data = _aligned_malloc(m_pitch * height, 32);
}
GSTextureSW::~GSTextureSW()
{
_aligned_free(m_data);
}
bool GSTextureSW::Update(const GSVector4i& r, const void* data, int pitch)
{
GSMap m;
if(m_data != NULL && Map(m, &r))
{
uint8* RESTRICT src = (uint8*)data;
uint8* RESTRICT dst = m.bits;
int rowbytes = r.width() << 2;
for(int h = r.height(); h > 0; h--, src += pitch, dst += m.pitch)
{
memcpy(dst, src, rowbytes);
}
Unmap();
return true;
}
return false;
}
bool GSTextureSW::Map(GSMap& m, const GSVector4i* r)
{
GSVector4i r2 = r != NULL ? *r : GSVector4i(0, 0, m_size.x, m_size.y);
if(m_data != NULL && r2.left >= 0 && r2.right <= m_size.x && r2.top >= 0 && r2.bottom <= m_size.y)
{
if(!_interlockedbittestandset(&m_mapped, 0))
{
m.bits = (uint8*)m_data + ((m_pitch * r2.top + r2.left) << 2);
m.pitch = m_pitch;
return true;
}
}
return false;
}
void GSTextureSW::Unmap()
{
m_mapped = 0;
}
#ifndef _WINDOWS
#pragma pack(push, 1)
struct BITMAPFILEHEADER
{
uint16 bfType;
uint32 bfSize;
uint16 bfReserved1;
uint16 bfReserved2;
uint32 bfOffBits;
};
struct BITMAPINFOHEADER
{
uint32 biSize;
int32 biWidth;
int32 biHeight;
uint16 biPlanes;
uint16 biBitCount;
uint32 biCompression;
uint32 biSizeImage;
int32 biXPelsPerMeter;
int32 biYPelsPerMeter;
uint32 biClrUsed;
uint32 biClrImportant;
};
#define BI_RGB 0
#pragma pack(pop)
#endif
#ifdef ENABLE_OGL_PNG
#include "png++/png.hpp"
void GSTextureSW::SavePNG(const string& fn) {
png::image<png::rgba_pixel> img(m_size.x, m_size.y);
uint8* data = (uint8*)m_data;
for(int h = 0; h < m_size.y; h++, data += m_pitch) {
for (int w = 0; w < m_size.x; w++) {
png::rgba_pixel pixel(data[4*w+0], data[4*w+1], data[4*w+2], data[4*w+3]);
img.set_pixel(w, h, pixel);
}
}
std::string rename = fn;
img.write(rename.replace(fn.length()-3, 3, "png"));
}
#endif
bool GSTextureSW::Save(const string& fn, bool dds)
{
if(dds) return false; // not implemented
#ifdef ENABLE_OGL_PNG
SavePNG(fn);
return true;
#else
if(FILE* fp = fopen(fn.c_str(), "wb"))
{
BITMAPINFOHEADER bih;
memset(&bih, 0, sizeof(bih));
bih.biSize = sizeof(bih);
bih.biWidth = m_size.x;
bih.biHeight = m_size.y;
bih.biPlanes = 1;
bih.biBitCount = 32;
bih.biCompression = BI_RGB;
bih.biSizeImage = m_size.x * m_size.y << 2;
BITMAPFILEHEADER bfh;
memset(&bfh, 0, sizeof(bfh));
uint8* bfType = (uint8*)&bfh.bfType;
// bfh.bfType = 'MB';
bfType[0] = 0x42;
bfType[1] = 0x4d;
bfh.bfOffBits = sizeof(bfh) + sizeof(bih);
bfh.bfSize = bfh.bfOffBits + bih.biSizeImage;
bfh.bfReserved1 = bfh.bfReserved2 = 0;
fwrite(&bfh, 1, sizeof(bfh), fp);
fwrite(&bih, 1, sizeof(bih), fp);
uint8* data = (uint8*)m_data + (m_size.y - 1) * m_pitch;
for(int h = m_size.y; h > 0; h--, data -= m_pitch)
{
for(int i = 0; i < m_size.x; i++)
{
uint32 c = ((uint32*)data)[i];
c = (c & 0xff00ff00) | ((c & 0x00ff0000) >> 16) | ((c & 0x000000ff) << 16);
fwrite(&c, 1, sizeof(c), fp);
}
// fwrite(data, 1, m_size.x << 2, fp); // TODO: swap red-blue?
}
fclose(fp);
return true;
}
return false;
#endif
}