2
#include <thin3d/thin3d.h>
4
#include "base/logging.h"
5
#include "image/zim_load.h"
6
#include "image/png_load.h"
8
#include "ext/jpge/jpgd.h"
10
// ================================== PIXEL/FRAGMENT SHADERS
12
// The Vulkan ones can be re-used with modern GL later if desired, as they're just GLSL.
14
static const char * const glsl_fsTexCol =
16
"precision lowp float;\n"
18
"varying vec4 oColor0;\n"
19
"varying vec2 oTexCoord0;\n"
20
"uniform sampler2D Sampler0;\n"
21
"void main() { gl_FragColor = texture2D(Sampler0, oTexCoord0) * oColor0; }\n";
23
static const char * const hlslFsTexCol =
24
"struct PS_INPUT { float4 color : COLOR0; float2 uv : TEXCOORD0; };\n"
25
"sampler2D Sampler0 : register(s0);\n"
26
"float4 main(PS_INPUT input) : COLOR0 {\n"
27
" return input.color * tex2D(Sampler0, input.uv);\n"
30
static const char * const vulkan_fsTexCol =
32
"#extension GL_ARB_separate_shader_objects : enable\n"
33
"#extension GL_ARB_shading_language_420pack : enable\n"
34
"layout(location = 0) in vec4 oColor0;\n"
35
"layout(location = 1) in vec2 oTexCoord0;\n"
36
"layout(location = 0) out vec4 fragColor0\n;"
37
"layout(set = 0, binding = 1) uniform sampler2D Sampler0;\n"
38
"void main() { fragColor0 = texture(Sampler0, oTexCoord0) * oColor0; }\n";
40
static const char * const glsl_fsCol =
42
"precision lowp float;\n"
44
"varying vec4 oColor0;\n"
45
"void main() { gl_FragColor = oColor0; }\n";
47
static const char * const hlslFsCol =
48
"struct PS_INPUT { float4 color : COLOR0; };\n"
49
"float4 main(PS_INPUT input) : COLOR0 {\n"
50
" return input.color;\n"
53
static const char * const vulkan_fsCol =
55
"#extension GL_ARB_separate_shader_objects : enable\n"
56
"#extension GL_ARB_shading_language_420pack : enable\n"
57
"layout(location = 0) in vec4 oColor0;\n"
58
"layout(location = 0) out vec4 fragColor0\n;"
59
"void main() { fragColor0 = oColor0; }\n";
63
// ================================== VERTEX SHADERS
65
static const char * const glsl_vsCol =
66
"attribute vec3 Position;\n"
67
"attribute vec4 Color0;\n"
68
"varying vec4 oColor0;\n"
69
"uniform mat4 WorldViewProj;\n"
71
" gl_Position = WorldViewProj * vec4(Position, 1.0);\n"
72
" oColor0 = Color0;\n"
75
static const char * const hlslVsCol =
76
"struct VS_INPUT { float3 Position : POSITION; float4 Color0 : COLOR0; };\n"
77
"struct VS_OUTPUT { float4 Position : POSITION; float4 Color0 : COLOR0; };\n"
78
"float4x4 WorldViewProj;\n"
79
"VS_OUTPUT main(VS_INPUT input) {\n"
80
" VS_OUTPUT output;\n"
81
" output.Position = mul(float4(input.Position, 1.0), WorldViewProj);\n"
82
" output.Color0 = input.Color0;\n"
86
static const char * const vulkan_vsCol =
88
"#extension GL_ARB_separate_shader_objects : enable\n"
89
"#extension GL_ARB_shading_language_420pack : enable\n"
90
"layout (std140, set = 0, binding = 0) uniform bufferVals {\n"
91
" mat4 WorldViewProj;\n"
93
"layout (location = 0) in vec4 pos;\n"
94
"layout (location = 1) in vec4 inColor;\n"
95
"layout (location = 0) out vec4 outColor;\n"
96
"out gl_PerVertex { vec4 gl_Position; };\n"
98
" outColor = inColor;\n"
99
" gl_Position = myBufferVals.WorldViewProj * pos;\n"
103
static const char * const glsl_vsTexCol =
104
"attribute vec3 Position;\n"
105
"attribute vec4 Color0;\n"
106
"attribute vec2 TexCoord0;\n"
107
"varying vec4 oColor0;\n"
108
"varying vec2 oTexCoord0;\n"
109
"uniform mat4 WorldViewProj;\n"
111
" gl_Position = WorldViewProj * vec4(Position, 1.0);\n"
112
" oColor0 = Color0;\n"
113
" oTexCoord0 = TexCoord0;\n"
116
static const char * const hlslVsTexCol =
117
"struct VS_INPUT { float3 Position : POSITION; float2 Texcoord0 : TEXCOORD0; float4 Color0 : COLOR0; };\n"
118
"struct VS_OUTPUT { float4 Position : POSITION; float2 Texcoord0 : TEXCOORD0; float4 Color0 : COLOR0; };\n"
119
"float4x4 WorldViewProj;\n"
120
"VS_OUTPUT main(VS_INPUT input) {\n"
121
" VS_OUTPUT output;\n"
122
" output.Position = mul(float4(input.Position, 1.0), WorldViewProj);\n"
123
" output.Texcoord0 = input.Texcoord0;\n"
124
" output.Color0 = input.Color0;\n"
128
static const char * const vulkan_vsTexCol =
130
"#extension GL_ARB_separate_shader_objects : enable\n"
131
"#extension GL_ARB_shading_language_420pack : enable\n"
132
"layout (std140, set = 0, binding = 0) uniform bufferVals {\n"
133
" mat4 WorldViewProj;\n"
135
"layout (location = 0) in vec4 pos;\n"
136
"layout (location = 1) in vec4 inColor;\n"
137
"layout (location = 2) in vec2 inTexCoord;\n"
138
"layout (location = 0) out vec4 outColor;\n"
139
"layout (location = 1) out vec2 outTexCoord;\n"
140
"out gl_PerVertex { vec4 gl_Position; };\n"
142
" outColor = inColor;\n"
143
" outTexCoord = inTexCoord;\n"
144
" gl_Position = myBufferVals.WorldViewProj * pos;\n"
148
void Thin3DContext::CreatePresets() {
149
// Build prebuilt objects
150
T3DBlendStateDesc off = { false };
151
T3DBlendStateDesc additive = { true, T3DBlendEquation::ADD, T3DBlendFactor::ONE, T3DBlendFactor::ONE, T3DBlendEquation::ADD, T3DBlendFactor::ONE, T3DBlendFactor::ZERO };
152
T3DBlendStateDesc standard_alpha = { true, T3DBlendEquation::ADD, T3DBlendFactor::SRC_ALPHA, T3DBlendFactor::ONE_MINUS_SRC_ALPHA, T3DBlendEquation::ADD, T3DBlendFactor::ONE, T3DBlendFactor::ZERO };
153
T3DBlendStateDesc premul_alpha = { true, T3DBlendEquation::ADD, T3DBlendFactor::ONE, T3DBlendFactor::ONE_MINUS_SRC_ALPHA, T3DBlendEquation::ADD, T3DBlendFactor::ONE, T3DBlendFactor::ZERO };
155
bsPresets_[BS_OFF] = CreateBlendState(off);
156
bsPresets_[BS_ADDITIVE] = CreateBlendState(additive);
157
bsPresets_[BS_STANDARD_ALPHA] = CreateBlendState(standard_alpha);
158
bsPresets_[BS_PREMUL_ALPHA] = CreateBlendState(premul_alpha);
160
T3DSamplerStateDesc nearest = { CLAMP, CLAMP, NEAREST, NEAREST, NEAREST };
161
T3DSamplerStateDesc linear = { CLAMP, CLAMP, LINEAR, LINEAR, NEAREST };
163
sampsPresets_[SAMPS_NEAREST] = CreateSamplerState(nearest);
164
sampsPresets_[SAMPS_LINEAR] = CreateSamplerState(linear);
166
vsPresets_[VS_TEXTURE_COLOR_2D] = CreateVertexShader(glsl_vsTexCol, hlslVsTexCol, vulkan_vsTexCol);
167
vsPresets_[VS_COLOR_2D] = CreateVertexShader(glsl_vsCol, hlslVsCol, vulkan_vsCol);
169
fsPresets_[FS_TEXTURE_COLOR_2D] = CreateFragmentShader(glsl_fsTexCol, hlslFsTexCol, vulkan_fsTexCol);
170
fsPresets_[FS_COLOR_2D] = CreateFragmentShader(glsl_fsCol, hlslFsCol, vulkan_fsCol);
172
ssPresets_[SS_TEXTURE_COLOR_2D] = CreateShaderSet(vsPresets_[VS_TEXTURE_COLOR_2D], fsPresets_[FS_TEXTURE_COLOR_2D]);
173
ssPresets_[SS_COLOR_2D] = CreateShaderSet(vsPresets_[VS_COLOR_2D], fsPresets_[FS_COLOR_2D]);
176
Thin3DContext::~Thin3DContext() {
177
for (int i = 0; i < VS_MAX_PRESET; i++) {
179
vsPresets_[i]->Release();
182
for (int i = 0; i < FS_MAX_PRESET; i++) {
184
fsPresets_[i]->Release();
187
for (int i = 0; i < BS_MAX_PRESET; i++) {
189
bsPresets_[i]->Release();
192
for (int i = 0; i < SS_MAX_PRESET; i++) {
194
ssPresets_[i]->Release();
197
for (int i = 0; i < SAMPS_MAX_PRESET; i++) {
198
if (sampsPresets_[i]) {
199
sampsPresets_[i]->Release();
204
static T3DImageFormat ZimToT3DFormat(int zim) {
206
case ZIM_ETC1: return T3DImageFormat::ETC1;
207
case ZIM_RGBA8888: return T3DImageFormat::RGBA8888;
208
case ZIM_LUMINANCE: return T3DImageFormat::LUMINANCE;
209
default: return T3DImageFormat::RGBA8888;
213
static T3DImageType DetectImageFileType(const uint8_t *data, size_t size) {
214
if (!memcmp(data, "ZIMG", 4)) {
216
} else if (!memcmp(data, "\x89\x50\x4E\x47", 4)) {
218
} else if (!memcmp(data, "\xff\xd8\xff\xe0", 4)) {
225
static bool LoadTextureLevels(const uint8_t *data, size_t size, T3DImageType type, int width[16], int height[16], int *num_levels, T3DImageFormat *fmt, uint8_t *image[16], int *zim_flags) {
226
if (type == DETECT) {
227
type = DetectImageFileType(data, size);
229
if (type == TYPE_UNKNOWN) {
230
ELOG("File has unknown format");
240
*num_levels = LoadZIMPtr((const uint8_t *)data, size, width, height, zim_flags, image);
241
*fmt = ZimToT3DFormat(*zim_flags & ZIM_FORMAT_MASK);
246
if (1 == pngLoadPtr((const unsigned char *)data, size, &width[0], &height[0], &image[0], false)) {
254
int actual_components = 0;
255
unsigned char *jpegBuf = jpgd::decompress_jpeg_image_from_memory(data, (int)size, &width[0], &height[0], &actual_components, 4);
259
image[0] = (uint8_t *)jpegBuf;
265
ELOG("Unknown image format");
269
return *num_levels > 0;
272
bool Thin3DTexture::LoadFromFileData(const uint8_t *data, size_t dataSize, T3DImageType type) {
273
int width[16], height[16];
274
uint8_t *image[16] = { nullptr };
280
if (!LoadTextureLevels(data, dataSize, type, width, height, &num_levels, &fmt, image, &zim_flags)) {
284
if (num_levels < 0 || num_levels >= 16) {
285
ELOG("Invalid num_levels: %d. Falling back to one. Image: %dx%d", num_levels, width[0], height[0]);
289
Create(LINEAR2D, fmt, width[0], height[0], 1, num_levels);
290
for (int i = 0; i < num_levels; i++) {
292
SetImageData(0, 0, 0, width[i], height[i], 1, i, width[i] * 4, image[i]);
295
ELOG("Missing image level %i", i);
303
bool Thin3DTexture::LoadFromFile(const std::string &filename, T3DImageType type) {
306
uint8_t *buffer = VFSReadFile(filename.c_str(), &fileSize);
310
bool retval = LoadFromFileData(buffer, fileSize, type);
312
filename_ = filename;
314
ELOG("%s: Failed to load texture %s", __FUNCTION__, filename.c_str());
320
Thin3DTexture *Thin3DContext::CreateTextureFromFile(const char *filename, T3DImageType type) {
321
Thin3DTexture *tex = CreateTexture();
322
if (!tex->LoadFromFile(filename, type)) {
329
// TODO: Remove the code duplication between this and LoadFromFileData
330
Thin3DTexture *Thin3DContext::CreateTextureFromFileData(const uint8_t *data, int size, T3DImageType type) {
331
int width[16], height[16];
335
uint8_t *image[16] = { nullptr };
337
if (!LoadTextureLevels(data, size, type, width, height, &num_levels, &fmt, image, &zim_flags)) {
341
Thin3DTexture *tex = CreateTexture(LINEAR2D, fmt, width[0], height[0], 1, num_levels);
342
for (int i = 0; i < num_levels; i++) {
343
tex->SetImageData(0, 0, 0, width[i], height[i], 1, i, width[i] * 4, image[i]);
347
tex->Finalize(zim_flags);