2021-01-13 17:48:25 +00:00
|
|
|
#include "StdAfx.h"
|
|
|
|
#include "frontends/libretro/retroframe.h"
|
|
|
|
#include "frontends/libretro/environment.h"
|
|
|
|
|
|
|
|
#include "Interface.h"
|
|
|
|
#include "Core.h"
|
|
|
|
#include "Utilities.h"
|
|
|
|
|
2021-01-20 18:17:34 +00:00
|
|
|
#include <fstream>
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
|
|
|
|
void readFileToBuffer(const std::string & filename, std::vector<char> & buffer)
|
|
|
|
{
|
|
|
|
std::ifstream file(filename.c_str(), std::ios::binary | std::ios::ate);
|
|
|
|
const std::streamsize size = file.tellg();
|
|
|
|
file.seekg(0, std::ios::beg);
|
|
|
|
|
|
|
|
buffer.resize(size);
|
|
|
|
file.read(buffer.data(), size);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
T getAs(const std::vector<char> & buffer, const size_t offset)
|
|
|
|
{
|
|
|
|
if (offset + sizeof(T) > buffer.size())
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Invalid bitmap");
|
|
|
|
}
|
|
|
|
const T * ptr = reinterpret_cast<const T *>(buffer.data() + offset);
|
|
|
|
return * ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// libretro cannot parse BMP with 1 bpp
|
|
|
|
// simple version implemented here
|
|
|
|
bool getBitmapData(const std::vector<char> & buffer, int32_t & width, int32_t & height, uint16_t & bpp, const char * & data, uint32_t & size)
|
|
|
|
{
|
|
|
|
if (buffer.size() < 2)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (buffer[0] != 0x42 || buffer[1] != 0x4D)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const uint32_t fileSize = getAs<uint32_t>(buffer, 2);
|
|
|
|
if (fileSize != buffer.size())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const uint32_t offset = getAs<uint32_t>(buffer, 10);
|
|
|
|
const uint32_t header = getAs<uint32_t>(buffer, 14);
|
|
|
|
if (header != 40)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
width = getAs<int32_t>(buffer, 18);
|
|
|
|
height = getAs<int32_t>(buffer, 22);
|
|
|
|
bpp = getAs<uint16_t>(buffer, 28);
|
|
|
|
const uint32_t imageSize = getAs<uint32_t>(buffer, 34);
|
|
|
|
if (offset + imageSize > fileSize)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
data = buffer.data() + offset;
|
|
|
|
size = imageSize;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-02-25 16:24:52 +00:00
|
|
|
namespace ra2
|
2021-01-13 17:48:25 +00:00
|
|
|
{
|
|
|
|
|
2021-02-25 16:24:52 +00:00
|
|
|
RetroFrame::RetroFrame()
|
2021-01-13 17:48:25 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2021-02-25 16:24:52 +00:00
|
|
|
void RetroFrame::FrameRefreshStatus(int drawflags)
|
2021-01-13 17:48:25 +00:00
|
|
|
{
|
2021-02-25 16:24:52 +00:00
|
|
|
if (drawflags & DRAW_TITLE)
|
|
|
|
{
|
|
|
|
GetAppleWindowTitle();
|
|
|
|
display_message(g_pAppTitle.c_str());
|
|
|
|
}
|
2021-01-13 17:48:25 +00:00
|
|
|
}
|
|
|
|
|
2021-02-25 16:24:52 +00:00
|
|
|
void RetroFrame::VideoPresentScreen()
|
|
|
|
{
|
|
|
|
// this should not be necessary
|
|
|
|
// either libretro handles it
|
|
|
|
// or we should change AW
|
|
|
|
// but for now, there is no alternative
|
|
|
|
for (size_t row = 0; row < myHeight; ++row)
|
|
|
|
{
|
|
|
|
const uint8_t * src = myFrameBuffer + row * myPitch;
|
|
|
|
uint8_t * dst = myVideoBuffer.data() + (myHeight - row - 1) * myPitch;
|
|
|
|
memcpy(dst, src, myPitch);
|
|
|
|
}
|
2021-01-13 17:48:25 +00:00
|
|
|
|
2021-02-25 16:24:52 +00:00
|
|
|
video_cb(myVideoBuffer.data() + myOffset, myBorderlessWidth, myBorderlessHeight, myPitch);
|
|
|
|
}
|
2021-01-13 17:48:25 +00:00
|
|
|
|
2021-02-25 16:24:52 +00:00
|
|
|
void RetroFrame::Initialize()
|
|
|
|
{
|
|
|
|
LinuxFrame::Initialize();
|
|
|
|
FrameRefreshStatus(DRAW_TITLE);
|
2021-01-13 17:48:25 +00:00
|
|
|
|
2021-02-25 16:24:52 +00:00
|
|
|
Video & video = GetVideo();
|
2021-01-13 17:48:25 +00:00
|
|
|
|
2021-02-25 16:24:52 +00:00
|
|
|
myBorderlessWidth = video.GetFrameBufferBorderlessWidth();
|
|
|
|
myBorderlessHeight = video.GetFrameBufferBorderlessHeight();
|
|
|
|
const size_t borderWidth = video.GetFrameBufferBorderWidth();
|
|
|
|
const size_t borderHeight = video.GetFrameBufferBorderHeight();
|
|
|
|
const size_t width = video.GetFrameBufferWidth();
|
|
|
|
myHeight = video.GetFrameBufferHeight();
|
2021-01-13 17:48:25 +00:00
|
|
|
|
2021-02-25 16:24:52 +00:00
|
|
|
myFrameBuffer = video.GetFrameBuffer();
|
2021-01-13 17:48:25 +00:00
|
|
|
|
2021-02-25 16:24:52 +00:00
|
|
|
myPitch = width * sizeof(bgra_t);
|
|
|
|
myOffset = (width * borderHeight + borderWidth) * sizeof(bgra_t);
|
2021-01-13 17:48:25 +00:00
|
|
|
|
2021-02-25 16:24:52 +00:00
|
|
|
const size_t size = myHeight * myPitch;
|
|
|
|
myVideoBuffer.resize(size);
|
|
|
|
}
|
2021-01-20 18:17:34 +00:00
|
|
|
|
2021-02-25 16:24:52 +00:00
|
|
|
void RetroFrame::Destroy()
|
|
|
|
{
|
|
|
|
LinuxFrame::Destroy();
|
|
|
|
myFrameBuffer = nullptr;
|
|
|
|
myVideoBuffer.clear();
|
|
|
|
}
|
2021-01-20 18:17:34 +00:00
|
|
|
|
2021-02-25 16:24:52 +00:00
|
|
|
void RetroFrame::GetBitmap(LPCSTR lpBitmapName, LONG cb, LPVOID lpvBits)
|
2021-01-20 18:17:34 +00:00
|
|
|
{
|
2021-02-25 16:24:52 +00:00
|
|
|
const std::string filename = getBitmapFilename(lpBitmapName);
|
|
|
|
const std::string path = myResourcePath + filename;
|
2021-01-20 18:17:34 +00:00
|
|
|
|
2021-02-25 16:24:52 +00:00
|
|
|
std::vector<char> buffer;
|
|
|
|
readFileToBuffer(path, buffer);
|
2021-01-20 18:17:34 +00:00
|
|
|
|
2021-02-25 16:24:52 +00:00
|
|
|
if (!buffer.empty())
|
2021-01-20 18:17:34 +00:00
|
|
|
{
|
2021-02-25 16:24:52 +00:00
|
|
|
int32_t width, height;
|
|
|
|
uint16_t bpp;
|
|
|
|
const char * data;
|
|
|
|
uint32_t size;
|
|
|
|
const bool res = getBitmapData(buffer, width, height, bpp, data, size);
|
|
|
|
|
|
|
|
log_cb(RETRO_LOG_INFO, "RA2: %s. %s = %dx%d, %dbpp\n", __FUNCTION__, path.c_str(),
|
|
|
|
width, height, bpp);
|
|
|
|
|
|
|
|
if (res && height > 0 && size <= cb)
|
2021-01-20 18:17:34 +00:00
|
|
|
{
|
2021-02-25 16:24:52 +00:00
|
|
|
const size_t length = size / height;
|
|
|
|
// rows are stored upside down
|
|
|
|
char * out = static_cast<char *>(lpvBits);
|
|
|
|
for (size_t row = 0; row < height; ++row)
|
|
|
|
{
|
|
|
|
const char * src = data + row * length;
|
|
|
|
char * dst = out + (height - row - 1) * length;
|
|
|
|
memcpy(dst, src, length);
|
|
|
|
}
|
|
|
|
return;
|
2021-01-20 18:17:34 +00:00
|
|
|
}
|
|
|
|
}
|
2021-02-25 16:24:52 +00:00
|
|
|
|
|
|
|
CommonFrame::GetBitmap(lpBitmapName, cb, lpvBits);
|
2021-01-20 18:17:34 +00:00
|
|
|
}
|
|
|
|
|
2021-02-25 16:24:52 +00:00
|
|
|
int RetroFrame::FrameMessageBox(LPCSTR lpText, LPCSTR lpCaption, UINT uType)
|
|
|
|
{
|
|
|
|
log_cb(RETRO_LOG_INFO, "RA2: %s: %s - %s\n", __FUNCTION__, lpCaption, lpText);
|
|
|
|
return IDOK;
|
|
|
|
}
|
2021-01-20 18:17:34 +00:00
|
|
|
|
|
|
|
}
|