runtime: CMake-ify gx

This commit is contained in:
Michael Fabian 'Xaymar' Dirks
2019-01-18 17:03:37 +01:00
parent 28598fae6b
commit a16218e1d5
74 changed files with 6493 additions and 5286 deletions
+600
View File
@@ -0,0 +1,600 @@
#include "ddutil.hpp"
#include "GraphicsRuntime.hpp"
#include "asmcoder.hpp"
#include "gxcanvas.hpp"
#include "gxruntime.hpp"
#include "std.hpp"
#define FREEIMAGE_LIB
#include <freeimage.h>
extern gxRuntime* gx_runtime;
static AsmCoder asm_coder;
static void calcShifts(unsigned mask, unsigned char* shr, unsigned char* shl)
{
if (mask) {
for (*shl = 0; !(mask & 1); ++*shl, mask >>= 1) {
}
for (*shr = 8; mask & 1; --*shr, mask >>= 1) {
}
} else
*shr = *shl = 0;
}
PixelFormat::~PixelFormat()
{
if (plot_code) {
VirtualFree(plot_code, 0, MEM_RELEASE);
}
}
void PixelFormat::setFormat(const DDPIXELFORMAT& pf)
{
if (plot_code) {
VirtualFree(plot_code, 0, MEM_RELEASE);
}
if (!(pf.dwFlags & DDPF_RGB)) {
memset(this, 0, sizeof(*this));
return;
}
plot_code = (char*)VirtualAlloc(0, 128, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
point_code = plot_code + 64;
depth = pf.dwRGBBitCount;
amask = pf.dwRGBAlphaBitMask;
rmask = pf.dwRBitMask;
gmask = pf.dwGBitMask;
bmask = pf.dwBBitMask;
pitch = depth / 8;
argbfill = 0;
if (!amask)
argbfill |= 0xff000000;
if (!rmask)
argbfill |= 0x00ff0000;
if (!gmask)
argbfill |= 0x0000ff00;
if (!bmask)
argbfill |= 0x000000ff;
calcShifts(amask, &ashr, &ashl);
ashr += 24;
calcShifts(rmask, &rshr, &rshl);
rshr += 16;
calcShifts(gmask, &gshr, &gshl);
gshr += 8;
calcShifts(bmask, &bshr, &bshl);
plot = (Plot)(void*)plot_code;
point = (Point)(void*)point_code;
asm_coder.CodePlot(plot_code, depth, amask, rmask, gmask, bmask);
asm_coder.CodePoint(point_code, depth, amask, rmask, gmask, bmask);
}
static void adjustTexSize(int* width, int* height, IDirect3DDevice7* dir3dDev, bool forcePOT = true)
{
D3DDEVICEDESC7 ddDesc = {0};
if (dir3dDev->GetCaps(&ddDesc) < 0) {
*width = *height = 256;
return;
}
int w = *width, h = *height, min, max;
if (ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2
|| ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL || forcePOT) {
// DirectX Device doesn't support Non Power-Of-Two Textures.
for (w = 1; w < *width; w <<= 1) {
}
for (h = 1; h < *height; h <<= 1) {
}
} else if (ddDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY) {
// DirectX Device only supports Square Textures;
if (w > h)
h = w;
else
w = h;
}
//check aspect ratio
if (max = ddDesc.dwMaxTextureAspectRatio) {
int asp = w > h ? w / h : h / w;
if (asp > max) {
if (w > h)
h = w / max;
else
w = h / max;
}
}
//clamp size
if ((min = ddDesc.dwMinTextureWidth) && w < min)
w = min;
if ((min = ddDesc.dwMinTextureHeight) && h < min)
h = min;
if ((max = ddDesc.dwMaxTextureWidth) && w > max)
w = max;
if ((max = ddDesc.dwMaxTextureHeight) && h > max)
h = max;
*width = w;
*height = h;
}
static IDirectDrawSurface7* createSurface(int width, int height, int pitch, void* bits, IDirectDraw7* dirDraw)
{
DDSURFACEDESC2 desc = {sizeof(desc)};
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_LPSURFACE | DDSD_PITCH | DDSD_PIXELFORMAT | DDSD_CAPS;
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
desc.dwWidth = width;
desc.dwHeight = height;
desc.lPitch = pitch;
desc.lpSurface = bits;
desc.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
desc.ddpfPixelFormat.dwRGBBitCount = 32;
desc.ddpfPixelFormat.dwRBitMask = 0xff0000;
desc.ddpfPixelFormat.dwGBitMask = 0x00ff00;
desc.ddpfPixelFormat.dwBBitMask = 0x0000ff;
desc.ddpfPixelFormat.dwRGBAlphaBitMask = 0xff000000;
IDirectDrawSurface7* surf;
if (dirDraw->CreateSurface(&desc, &surf, 0) >= 0)
return surf;
return 0;
}
static void buildMask(IDirectDrawSurface7* surf)
{
DDSURFACEDESC2 desc = {sizeof(desc)};
surf->Lock(0, &desc, DDLOCK_WAIT, 0);
unsigned char* surf_p = (unsigned char*)desc.lpSurface;
PixelFormat fmt(desc.ddpfPixelFormat);
for (DWORD y = 0; y < desc.dwHeight; ++y) {
unsigned char* p = surf_p;
for (DWORD x = 0; x < desc.dwWidth; ++x) {
unsigned argb = fmt.getPixel(p);
unsigned rgb = argb & 0xffffff;
unsigned a = rgb ? 0xff000000 : 0;
fmt.setPixel(p, a | rgb);
p += fmt.getPitch();
}
surf_p += desc.lPitch;
}
surf->Unlock(0);
}
static void buildAlpha(IDirectDrawSurface7* surf, bool whiten)
{
DDSURFACEDESC2 desc = {sizeof(desc)};
surf->Lock(0, &desc, DDLOCK_WAIT, 0);
unsigned char* surf_p = (unsigned char*)desc.lpSurface;
PixelFormat fmt(desc.ddpfPixelFormat);
for (DWORD y = 0; y < desc.dwHeight; ++y) {
unsigned char* p = surf_p;
for (DWORD x = 0; x < desc.dwWidth; ++x) {
unsigned argb = fmt.getPixel(p);
unsigned alpha = (((argb >> 16) & 0xff) + ((argb >> 8) & 0xff) + (argb & 0xff)) / 3;
argb = (alpha << 24) | (argb & 0xffffff);
if (whiten)
argb |= 0xffffff;
fmt.setPixel(p, argb);
p += fmt.getPitch();
}
surf_p += desc.lPitch;
}
surf->Unlock(0);
}
void ddUtil::buildMipMaps(IDirectDrawSurface7* surf)
{
DDSURFACEDESC2 desc = {sizeof(desc)};
surf->GetSurfaceDesc(&desc);
if (!(desc.ddsCaps.dwCaps & DDSCAPS_TEXTURE))
return;
if (!(desc.ddpfPixelFormat.dwFlags & DDPF_RGB))
return;
DDSCAPS2 caps = {0};
caps.dwCaps = DDSCAPS_TEXTURE;
caps.dwCaps2 = DDSCAPS2_MIPMAPSUBLEVEL;
IDirectDrawSurface7 *src = surf, *dest;
while (src->GetAttachedSurface(&caps, &dest) >= 0) {
DDSURFACEDESC2 src_desc = {sizeof(src_desc)};
if (src->Lock(0, &src_desc, DDLOCK_WAIT, 0) < 0)
abort();
unsigned char* src_p = (unsigned char*)src_desc.lpSurface;
PixelFormat src_fmt(src_desc.ddpfPixelFormat);
DDSURFACEDESC2 dest_desc = {sizeof(dest_desc)};
if (dest->Lock(0, &dest_desc, DDLOCK_WAIT, 0) < 0)
abort();
unsigned char* dest_p = (unsigned char*)dest_desc.lpSurface;
PixelFormat dest_fmt(dest_desc.ddpfPixelFormat);
if (src_desc.dwWidth == 1) {
for (DWORD y = 0; y < dest_desc.dwHeight; ++y) {
unsigned p1 = src_fmt.getPixel(src_p);
unsigned p2 = src_fmt.getPixel(src_p + src_desc.lPitch);
unsigned argb = ((p1 & 0xfefefefe) >> 1) + ((p2 & 0xfefefefe) >> 1);
argb += (((p1 & 0x01010101) + (p2 & 0x01010101)) >> 1) & 0x01010101;
dest_fmt.setPixel(dest_p, argb);
src_p += src_desc.lPitch * 2;
dest_p += dest_desc.lPitch;
}
} else if (src_desc.dwHeight == 1) {
for (DWORD x = 0; x < dest_desc.dwWidth; ++x) {
unsigned p1 = src_fmt.getPixel(src_p);
unsigned p2 = src_fmt.getPixel(src_p + src_fmt.getPitch());
unsigned argb = ((p1 & 0xfefefefe) >> 1) + ((p2 & 0xfefefefe) >> 1);
argb += (((p1 & 0x01010101) + (p2 & 0x01010101)) >> 1) & 0x01010101;
dest_fmt.setPixel(dest_p, argb);
src_p += src_fmt.getPitch() * 2;
dest_p += dest_fmt.getPitch();
}
} else {
for (DWORD y = 0; y < dest_desc.dwHeight; ++y) {
unsigned char* src_t = src_p;
unsigned char* dest_t = dest_p;
for (DWORD x = 0; x < dest_desc.dwWidth; ++x) {
unsigned p1 = src_fmt.getPixel(src_t);
unsigned p2 = src_fmt.getPixel(src_t + src_fmt.getPitch());
unsigned p3 = src_fmt.getPixel(src_t + src_desc.lPitch + src_fmt.getPitch());
unsigned p4 = src_fmt.getPixel(src_t + src_desc.lPitch);
unsigned argb = ((p1 & 0xfcfcfcfc) >> 2) + ((p2 & 0xfcfcfcfc) >> 2) + ((p3 & 0xfcfcfcfc) >> 2)
+ ((p4 & 0xfcfcfcfc) >> 2);
argb += (((p1 & 0x03030303) + (p2 & 0x03030303) + (p3 & 0x03030303) + (p4 & 0x03030303)) >> 2)
& 0x03030303;
dest_fmt.setPixel(dest_t, argb);
src_t += src_fmt.getPitch() * 2;
dest_t += dest_fmt.getPitch();
}
src_p += src_desc.lPitch * 2;
dest_p += dest_desc.lPitch;
}
}
src->Unlock(0);
dest->Unlock(0);
dest->Release();
src = dest;
}
}
void ddUtil::copy(IDirectDrawSurface7* dest, int dx, int dy, int dw, int dh, IDirectDrawSurface7* src, int sx, int sy,
int sw, int sh)
{
DDSURFACEDESC2 src_desc = {sizeof(src_desc)};
src->Lock(0, &src_desc, DDLOCK_WAIT, 0);
PixelFormat src_fmt(src_desc.ddpfPixelFormat);
unsigned char* src_p = (unsigned char*)src_desc.lpSurface;
src_p += src_desc.lPitch * sy + src_fmt.getPitch() * sx;
DDSURFACEDESC2 dest_desc = {sizeof(dest_desc)};
dest->Lock(0, &dest_desc, DDLOCK_WAIT, 0);
PixelFormat dest_fmt(dest_desc.ddpfPixelFormat);
unsigned char* dest_p = (unsigned char*)dest_desc.lpSurface;
dest_p += dest_desc.lPitch * dy + dest_fmt.getPitch() * dx;
for (int y = 0; y < dh; ++y) {
unsigned char* dest = dest_p;
unsigned char* src = src_p + src_desc.lPitch * (y * sh / dh);
for (int x = 0; x < dw; ++x) {
dest_fmt.setPixel(dest, src_fmt.getPixel(src + src_fmt.getPitch() * (x * sw / dw)));
dest += dest_fmt.getPitch();
}
dest_p += dest_desc.lPitch;
}
src->Unlock(0);
dest->Unlock(0);
}
IDirectDrawSurface7* ddUtil::createSurface(int w, int h, int flags, gxGraphics* gfx)
{
int hi = flags & gxCanvas::CANVAS_TEX_HICOLOR ? 1 : 0;
DDSURFACEDESC2 desc = {sizeof(desc)};
// Texture Size
desc.dwFlags = DDSD_CAPS;
if (w) {
desc.dwWidth = w;
desc.dwFlags |= DDSD_WIDTH;
}
if (h) {
desc.dwHeight = h;
desc.dwFlags |= DDSD_HEIGHT;
}
// Format
if (flags & gxCanvas::CANVAS_TEXTURE) {
// Flags guaranteed:
// - CANVAS_TEX_RGB
// - CANVAS_TEX_ALPHA
// - CANVAS_TEXTURE
desc.dwFlags |= DDSCAPS_3DDEVICE | DDSD_PIXELFORMAT;
desc.ddsCaps.dwCaps |= DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY;
if (flags & gxCanvas::CANVAS_TEXTURE) {
desc.ddpfPixelFormat = gfx->primFmt;
} else {
desc.ddpfPixelFormat = gfx->texRGBAlphaFmt[hi];
}
} else {
if (flags & gxCanvas::CANVAS_TEX_MASK) {
desc.dwFlags |= DDSD_PIXELFORMAT;
desc.ddpfPixelFormat = gfx->texRGBMaskFmt[hi];
} else if (flags & gxCanvas::CANVAS_TEX_RGB) {
desc.dwFlags |= DDSD_PIXELFORMAT;
desc.ddpfPixelFormat = (flags & gxCanvas::CANVAS_TEX_ALPHA) ? gfx->texRGBAlphaFmt[hi] : gfx->texRGBFmt[hi];
} else if (flags & gxCanvas::CANVAS_TEX_ALPHA) {
desc.dwFlags |= DDSD_PIXELFORMAT;
desc.ddpfPixelFormat = gfx->texAlphaFmt[hi];
} else if (flags & gxCanvas::CANVAS_TEXTURE) {
desc.dwFlags |= DDSD_PIXELFORMAT;
desc.ddpfPixelFormat = gfx->primFmt;
}
}
// Cube Map
if (flags & (gxCanvas::CANVAS_TEX_CUBE)) {
desc.ddsCaps.dwCaps |= DDSCAPS_COMPLEX;
desc.ddsCaps.dwCaps2 |= DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALLFACES;
}
// Video Memory
if (!(flags & gxCanvas::CANVAS_TEX_VIDMEM)) {
desc.ddsCaps.dwCaps2 |= DDSCAPS2_TEXTUREMANAGE;
if (flags & gxCanvas::CANVAS_TEX_MIPMAP) {
desc.ddsCaps.dwCaps |= DDSCAPS_MIPMAP | DDSCAPS_COMPLEX;
}
}
// Texture Move
if ((flags & gxCanvas::CANVAS_TEXTURE) || (flags & gxCanvas::CANVAS_3DRENDER)) {
desc.ddsCaps.dwCaps |= DDSCAPS_TEXTURE;
if (!(flags & gxCanvas::CANVAS_TEX_VIDMEM)) {
desc.ddsCaps.dwCaps2 |= DDSCAPS2_TEXTUREMANAGE;
if (flags & gxCanvas::CANVAS_TEX_MIPMAP) {
desc.ddsCaps.dwCaps |= DDSCAPS_MIPMAP | DDSCAPS_COMPLEX;
}
}
if (flags & (gxCanvas::CANVAS_TEX_CUBE)) {
desc.ddsCaps.dwCaps |= DDSCAPS_COMPLEX;
desc.ddsCaps.dwCaps2 |= DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALLFACES;
}
adjustTexSize((int*)&desc.dwWidth, (int*)&desc.dwHeight, gfx->dir3dDev, !(flags & (gxCanvas::CANVAS_TEX_NPOT)));
} else {
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
if (flags & gxCanvas::CANVAS_HIGHCOLOR) {
desc.dwFlags |= DDSD_PIXELFORMAT;
desc.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
desc.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
desc.ddpfPixelFormat.dwRGBBitCount = 32;
desc.ddpfPixelFormat.dwRBitMask = 0xff0000;
desc.ddpfPixelFormat.dwGBitMask = 0x00ff00;
desc.ddpfPixelFormat.dwBBitMask = 0x0000ff;
desc.ddpfPixelFormat.dwRGBAlphaBitMask = 0xff000000;
} else if (flags & gxCanvas::CANVAS_NONDISPLAY) {
desc.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
}
}
IDirectDrawSurface7* surf;
if (gfx->dirDraw->CreateSurface(&desc, &surf, 0) >= 0) {
return surf;
}
if (desc.ddsCaps.dwCaps & DDSCAPS_OFFSCREENPLAIN) {
if (!(desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)) {
//try again in system memory!
desc.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
if (gfx->dirDraw->CreateSurface(&desc, &surf, 0) >= 0)
return surf;
}
}
return 0;
}
//Tom Speed's DXTC loader
//
IDirectDrawSurface7* loadDXTC(const char* filename, gxGraphics* gfx)
{
HRESULT hr;
DDSURFACEDESC2 ddsd;
DDSURFACEDESC2 fileddsd;
char magicID[4];
FILE* fp;
/* try to open the file */
fp = fopen(filename, "rb");
if (!fp)
return NULL;
/* valid DDS? */
fread(magicID, 1, 4, fp);
if (strncmp(magicID, "DDS ", 4) != 0) {
fclose(fp);
return NULL;
}
/* get the DXTC file surface description */
fread(&fileddsd, sizeof(DDSURFACEDESC2), 1, fp);
if (fileddsd.dwSize != sizeof(DDSURFACEDESC2)) {
fclose(fp);
return NULL;
}
/* copy the fileddsd before we manipulate it so you
can get neccessary info you want about it later */
memcpy(&ddsd, &fileddsd, sizeof(DDSURFACEDESC2));
/* remove unwanted flags if they exist */
//not sure if this is needed, works without it though
//ddsd.dwFlags &= ~DDSD_LINEARSIZE;
int blockSize = 0;
int chunkSize = 0;
if (ddsd.ddpfPixelFormat.dwFourCC == FOURCC_DXT1)
blockSize = 8; // DXT1
if (ddsd.ddpfPixelFormat.dwFourCC == FOURCC_DXT3)
blockSize = 16; // DXT3
if (ddsd.ddpfPixelFormat.dwFourCC == FOURCC_DXT5)
blockSize = 16; // DXT5
/* if it isn't a format we support, exit */
if (blockSize == 0) {
fclose(fp);
return NULL;
}
/* add texture manage flag */
ddsd.ddsCaps.dwCaps2 |= DDSCAPS2_TEXTUREMANAGE;
/* Create the new DXTC surface using the DDSURFACEDESC2
we read in from the file */
IDirectDrawSurface7* newSurf = NULL;
hr = gfx->dirDraw->CreateSurface(&ddsd, &newSurf, NULL);
if (FAILED(hr)) {
fclose(fp);
return NULL;
}
/* Define what type of child surfaces we may wish
to access, in this case MipMaps */
DDSCAPS2 mipmapddsd;
ZeroMemory(&mipmapddsd, sizeof(DDSCAPS2));
mipmapddsd.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_MIPMAP | DDSCAPS_COMPLEX;
/* pointers used when iterating through mipmaps */
IDirectDrawSurface7* topDDS = NULL;
IDirectDrawSurface7* nextDDS = NULL;
topDDS = newSurf;
topDDS->AddRef();
while (TRUE) {
/* get a description of this surface */
hr = topDDS->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
if (FAILED(hr)) {
fclose(fp);
topDDS->Release();
newSurf->Release();
nextDDS->Release();
return NULL;
}
/* how big the raw data is for this surface */
chunkSize = ((ddsd.dwWidth + 3) / 4) * ((ddsd.dwHeight + 3) / 4) * blockSize;
/* read in the raw DXTC surface data */
if (!fread(ddsd.lpSurface, chunkSize, 1, fp)) {
fclose(fp);
topDDS->Release();
newSurf->Release();
nextDDS->Release();
return NULL;
}
topDDS->Unlock(NULL);
/* Get next mipmap in chain, or exit the loop if there's no more */
hr = topDDS->GetAttachedSurface(&mipmapddsd, &nextDDS);
if (FAILED(hr)) {
fclose(fp);
topDDS->Release();
break;
}
topDDS->Release();
topDDS = nextDDS;
nextDDS->Release();
}
return newSurf;
}
IDirectDrawSurface7* ddUtil::loadSurface(const std::string& f, int flags, gxGraphics* gfx)
{
int i = f.find(".dds");
if (i != string::npos && i + 4 == f.size()) {
//dds file!
IDirectDrawSurface7* surf = loadDXTC(f.c_str(), gfx);
return surf;
}
FreeImage_Initialise();
FREE_IMAGE_FORMAT fmt = FreeImage_GetFileType(f.c_str(), f.size());
if (fmt == FIF_UNKNOWN) {
int n = f.find(".");
if (n == string::npos)
return 0;
fmt = FreeImage_GetFileType(f.c_str());
if (fmt == FIF_UNKNOWN)
return 0;
}
FIBITMAP* t_dib = FreeImage_Load(fmt, f.c_str(), 0);
if (!t_dib)
return 0;
bool trans = FreeImage_GetBPP(t_dib) == 32 || FreeImage_IsTransparent(t_dib);
FIBITMAP* dib = FreeImage_ConvertTo32Bits(t_dib);
if (dib)
FreeImage_Unload(t_dib);
else
dib = t_dib;
int width = FreeImage_GetWidth(dib);
int height = FreeImage_GetHeight(dib);
int pitch = FreeImage_GetPitch(dib);
void* bits = FreeImage_GetBits(dib);
IDirectDrawSurface7* src = ::createSurface(width, height, pitch, bits, gfx->dirDraw);
if (!src) {
FreeImage_Unload(dib);
return 0;
}
if (flags & gxCanvas::CANVAS_TEX_ALPHA) {
if (flags & gxCanvas::CANVAS_TEX_MASK) {
buildMask(src);
} else if (!trans) {
buildAlpha(src, (flags & gxCanvas::CANVAS_TEX_RGB) ? false : true);
}
} else {
unsigned char* p = (unsigned char*)bits;
for (int k = 0; k < height; ++k) {
unsigned char* t = p + 3;
for (int j = 0; j < width; ++j) {
*t = 0xff;
t += 4;
}
p += pitch;
}
}
IDirectDrawSurface7* dest = createSurface(width, height, flags, gfx);
if (!dest) {
src->Release();
FreeImage_Unload(dib);
return 0;
}
int t_w = width, t_h = height;
if (flags & gxCanvas::CANVAS_TEXTURE)
adjustTexSize(&t_w, &t_h, gfx->dir3dDev, !(flags & (gxCanvas::CANVAS_TEX_NPOT)));
copy(dest, 0, 0, t_w, t_h, src, 0, height - 1, width, -height);
src->Release();
FreeImage_Unload(dib);
return dest;
}