ppsspp/thin3d/thin3d.cpp

265 lines
7.8 KiB
C++
Raw Normal View History

2014-09-06 08:11:52 -07:00
#include <string.h>
#include <thin3d/thin3d.h>
#include "base/logging.h"
#include "image/zim_load.h"
2014-08-17 21:28:34 +02:00
#include "image/png_load.h"
#include "file/vfs.h"
#include "ext/jpge/jpgd.h"
static const char * const glsl_fsTexCol =
"varying vec4 oColor0;\n"
"varying vec2 oTexCoord0;\n"
"uniform sampler2D Sampler0;\n"
"void main() { gl_FragColor = oColor0 * texture2D(Sampler0, oTexCoord0); }\n";
static const char * const hlslFsTexCol =
"struct PS_INPUT { float4 color : COLOR0; float2 uv : TEXCOORD0; };\n"
2014-08-22 21:26:46 +02:00
"sampler2D Sampler0 : register(s0);\n"
"float4 main(PS_INPUT input) : COLOR0 {\n"
2014-08-22 21:26:46 +02:00
" return input.color * tex2D(Sampler0, input.uv);\n"
"}\n";
static const char * const glsl_fsCol =
"varying vec4 oColor0;\n"
"void main() { gl_FragColor = oColor0; }\n";
static const char * const hlslFsCol =
"struct PS_INPUT { float4 color : COLOR0; };\n"
"float4 main(PS_INPUT input) : COLOR0 {\n"
" return input.color;\n"
"}\n";
static const char * const glsl_vsCol =
"attribute vec3 Position;\n"
"attribute vec4 Color0;\n"
"varying vec4 oColor0;\n"
"uniform mat4 WorldViewProj;\n"
"void main() {\n"
" gl_Position = WorldViewProj * vec4(Position, 1.0);\n"
" oColor0 = Color0;\n"
"}";
static const char * const hlslVsCol =
"struct VS_INPUT { float3 Position : POSITION; float4 Color0 : COLOR0; };\n"
"struct VS_OUTPUT { float4 Position : POSITION; float4 Color0 : COLOR0; };\n"
2014-08-17 21:28:34 +02:00
"float4x4 WorldViewProj;\n"
"VS_OUTPUT main(VS_INPUT input) {\n"
" VS_OUTPUT output;\n"
" output.Position = mul(float4(input.Position, 1.0), WorldViewProj);\n"
" output.Color0 = input.Color0;\n"
" return output;\n"
"}\n";
static const char * const glsl_vsTexCol =
"attribute vec3 Position;\n"
"attribute vec4 Color0;\n"
"attribute vec2 TexCoord0;\n"
"varying vec4 oColor0;\n"
"varying vec2 oTexCoord0;\n"
"uniform mat4 WorldViewProj;\n"
"void main() {\n"
" gl_Position = WorldViewProj * vec4(Position, 1.0);\n"
" oColor0 = Color0;\n"
" oTexCoord0 = TexCoord0;\n"
"}\n";
static const char * const hlslVsTexCol =
"struct VS_INPUT { float3 Position : POSITION; float2 Texcoord0 : TEXCOORD0; float4 Color0 : COLOR0; };\n"
"struct VS_OUTPUT { float4 Position : POSITION; float2 Texcoord0 : TEXCOORD0; float4 Color0 : COLOR0; };\n"
2014-08-17 21:28:34 +02:00
"float4x4 WorldViewProj;\n"
"VS_OUTPUT main(VS_INPUT input) {\n"
" VS_OUTPUT output;\n"
" output.Position = mul(float4(input.Position, 1.0), WorldViewProj);\n"
" output.Texcoord0 = input.Texcoord0;\n"
" output.Color0 = input.Color0;\n"
" return output;\n"
"}\n";
void Thin3DContext::CreatePresets() {
// Build prebuilt objects
T3DBlendStateDesc off = { false };
T3DBlendStateDesc additive = { true, T3DBlendEquation::ADD, T3DBlendFactor::ONE, T3DBlendFactor::ONE, T3DBlendEquation::ADD, T3DBlendFactor::ONE, T3DBlendFactor::ZERO };
T3DBlendStateDesc standard_alpha = { true, T3DBlendEquation::ADD, T3DBlendFactor::SRC_ALPHA, T3DBlendFactor::ONE_MINUS_SRC_ALPHA, T3DBlendEquation::ADD, T3DBlendFactor::ONE, T3DBlendFactor::ZERO };
T3DBlendStateDesc premul_alpha = { true, T3DBlendEquation::ADD, T3DBlendFactor::ONE, T3DBlendFactor::ONE_MINUS_SRC_ALPHA, T3DBlendEquation::ADD, T3DBlendFactor::ONE, T3DBlendFactor::ZERO };
bsPresets_[BS_OFF] = CreateBlendState(off);
bsPresets_[BS_ADDITIVE] = CreateBlendState(additive);
bsPresets_[BS_STANDARD_ALPHA] = CreateBlendState(standard_alpha);
bsPresets_[BS_PREMUL_ALPHA] = CreateBlendState(premul_alpha);
vsPresets_[VS_TEXTURE_COLOR_2D] = CreateVertexShader(glsl_vsTexCol, hlslVsTexCol);
vsPresets_[VS_COLOR_2D] = CreateVertexShader(glsl_vsCol, hlslVsCol);
fsPresets_[FS_TEXTURE_COLOR_2D] = CreateFragmentShader(glsl_fsTexCol, hlslFsTexCol);
fsPresets_[FS_COLOR_2D] = CreateFragmentShader(glsl_fsCol, hlslFsCol);
ssPresets_[SS_TEXTURE_COLOR_2D] = CreateShaderSet(vsPresets_[VS_TEXTURE_COLOR_2D], fsPresets_[FS_TEXTURE_COLOR_2D]);
ssPresets_[SS_COLOR_2D] = CreateShaderSet(vsPresets_[VS_COLOR_2D], fsPresets_[FS_COLOR_2D]);
}
Thin3DContext::~Thin3DContext() {
for (int i = 0; i < VS_MAX_PRESET; i++) {
if (vsPresets_[i]) {
vsPresets_[i]->Release();
}
}
for (int i = 0; i < FS_MAX_PRESET; i++) {
if (fsPresets_[i]) {
fsPresets_[i]->Release();
}
}
for (int i = 0; i < BS_MAX_PRESET; i++) {
if (bsPresets_[i]) {
bsPresets_[i]->Release();
}
}
for (int i = 0; i < SS_MAX_PRESET; i++) {
if (ssPresets_[i]) {
ssPresets_[i]->Release();
}
}
}
static T3DImageFormat ZimToT3DFormat(int zim) {
switch (zim) {
case ZIM_ETC1: return T3DImageFormat::ETC1;
case ZIM_RGBA8888: return T3DImageFormat::RGBA8888;
case ZIM_LUMINANCE: return T3DImageFormat::LUMINANCE;
default: return T3DImageFormat::RGBA8888;
}
}
static T3DImageType DetectImageFileType(const uint8_t *data, size_t size) {
if (!memcmp(data, "ZIMG", 4)) {
return ZIM;
} else if (!memcmp(data, "\x89\x50\x4E\x47", 4)) {
return PNG;
} else if (!memcmp(data, "\xff\xd8\xff\xe0", 4)) {
return JPEG;
} else {
return TYPE_UNKNOWN;
}
}
bool LoadTextureLevels(const uint8_t *data, int size, T3DImageType type, int width[16], int height[16], int *num_levels, T3DImageFormat *fmt, uint8_t *image[16], int *zim_flags) {
if (type == DETECT) {
type = DetectImageFileType(data, size);
}
if (type == TYPE_UNKNOWN) {
ELOG("File has unknown format");
return false;
}
*num_levels = 0;
*zim_flags = 0;
switch (type) {
case ZIM:
{
*num_levels = LoadZIMPtr((const uint8_t *)data, size, width, height, zim_flags, image);
*fmt = ZimToT3DFormat(*zim_flags & ZIM_FORMAT_MASK);
}
break;
case PNG:
if (1 == pngLoadPtr((const unsigned char *)data, size, &width[0], &height[0], &image[0], false)) {
*num_levels = 1;
*fmt = RGBA8888;
}
break;
case JPEG:
{
int actual_components = 0;
unsigned char *jpegBuf = jpgd::decompress_jpeg_image_from_memory(data, size, &width[0], &height[0], &actual_components, 4);
if (jpegBuf) {
*num_levels = 1;
*fmt = RGBA8888;
image[0] = (uint8_t *)jpegBuf;
}
}
break;
default:
ELOG("Unknown image format");
return false;
}
return *num_levels > 0;
}
bool Thin3DTexture::LoadFromFileData(const uint8_t *data, size_t dataSize, T3DImageType type) {
int width[16], height[16];
uint8_t *image[16] = { nullptr };
int num_levels;
int zim_flags;
T3DImageFormat fmt;
if (!LoadTextureLevels(data, dataSize, type, width, height, &num_levels, &fmt, image, &zim_flags)) {
return false;
}
Create(LINEAR2D, fmt, width[0], height[0], 1, num_levels);
for (int i = 0; i < num_levels; i++) {
if (image[i]) {
SetImageData(0, 0, 0, width[i], height[i], 1, i, width[i] * 4, image[i]);
free(image[i]);
} else {
ELOG("Missing image level %i", i);
}
}
Finalize(zim_flags);
return true;
}
bool Thin3DTexture::LoadFromFile(const std::string &filename, T3DImageType type) {
filename_ = "";
size_t fileSize;
uint8_t *buffer = VFSReadFile(filename.c_str(), &fileSize);
if (!buffer) {
return false;
}
bool retval = LoadFromFileData(buffer, fileSize, type);
if (retval) {
filename_ = filename;
2014-12-31 17:11:31 +01:00
} else {
ELOG("%s: Failed to load texture %s", __FUNCTION__, filename.c_str());
}
delete[] buffer;
return retval;
}
2014-08-17 21:28:34 +02:00
Thin3DTexture *Thin3DContext::CreateTextureFromFile(const char *filename, T3DImageType type) {
Thin3DTexture *tex = CreateTexture();
if (!tex->LoadFromFile(filename, type)) {
tex->Release();
return NULL;
}
2014-12-31 17:11:31 +01:00
return tex;
}
2014-12-31 17:11:31 +01:00
// TODO: Remove the code duplication between this and LoadFromFileData
Thin3DTexture *Thin3DContext::CreateTextureFromFileData(const uint8_t *data, int size, T3DImageType type) {
int width[16], height[16];
2014-08-17 21:28:34 +02:00
int num_levels = 0;
int zim_flags = 0;
2014-08-17 21:28:34 +02:00
T3DImageFormat fmt;
uint8_t *image[16] = { nullptr };
2014-08-17 21:28:34 +02:00
2014-12-31 17:11:31 +01:00
if (!LoadTextureLevels(data, size, type, width, height, &num_levels, &fmt, image, &zim_flags)) {
2014-08-17 21:28:34 +02:00
return NULL;
2014-12-31 17:11:31 +01:00
}
2014-08-17 21:28:34 +02:00
Thin3DTexture *tex = CreateTexture(LINEAR2D, fmt, width[0], height[0], 1, num_levels);
for (int i = 0; i < num_levels; i++) {
tex->SetImageData(0, 0, 0, width[i], height[i], 1, i, width[i] * 4, image[i]);
free(image[i]);
}
tex->Finalize(zim_flags);
return tex;
}