2014-06-16 21:18:15 +02:00
|
|
|
#include "core/fs/file_system.h"
|
|
|
|
#include "core/fs/ifile.h"
|
|
|
|
#include "core/log.h"
|
2015-07-27 00:42:25 +02:00
|
|
|
#include "core/math_utils.h"
|
2014-08-06 21:37:03 +02:00
|
|
|
#include "core/path_utils.h"
|
2014-07-24 23:05:17 +02:00
|
|
|
#include "core/profiler.h"
|
2014-06-16 21:18:15 +02:00
|
|
|
#include "core/resource_manager.h"
|
|
|
|
#include "core/resource_manager_base.h"
|
2015-08-17 23:45:26 +02:00
|
|
|
#include "renderer/texture.h"
|
|
|
|
#include "renderer/texture_manager.h"
|
2015-10-01 02:07:22 +02:00
|
|
|
#include <bgfx/bgfx.h>
|
2015-07-30 09:18:37 +02:00
|
|
|
#include <cmath>
|
2014-06-16 21:18:15 +02:00
|
|
|
|
|
|
|
namespace Lumix
|
|
|
|
{
|
|
|
|
|
|
|
|
|
2015-07-27 00:42:25 +02:00
|
|
|
#pragma pack(1)
|
|
|
|
struct TGAHeader
|
|
|
|
{
|
|
|
|
char idLength;
|
|
|
|
char colourMapType;
|
|
|
|
char dataType;
|
|
|
|
short int colourMapOrigin;
|
|
|
|
short int colourMapLength;
|
|
|
|
char colourMapDepth;
|
|
|
|
short int xOrigin;
|
|
|
|
short int yOrigin;
|
|
|
|
short int width;
|
|
|
|
short int height;
|
|
|
|
char bitsPerPixel;
|
|
|
|
char imageDescriptor;
|
|
|
|
};
|
2014-06-16 21:18:15 +02:00
|
|
|
#pragma pack()
|
|
|
|
|
|
|
|
|
2015-07-27 00:42:25 +02:00
|
|
|
Texture::Texture(const Path& path,
|
|
|
|
ResourceManager& resource_manager,
|
|
|
|
IAllocator& allocator)
|
2015-06-18 01:33:49 +02:00
|
|
|
: Resource(path, resource_manager, allocator)
|
|
|
|
, m_data_reference(0)
|
|
|
|
, m_allocator(allocator)
|
|
|
|
, m_data(m_allocator)
|
|
|
|
, m_BPP(-1)
|
2015-08-20 00:24:04 +02:00
|
|
|
, m_depth(-1)
|
2015-06-18 01:33:49 +02:00
|
|
|
{
|
2015-10-04 13:37:29 +02:00
|
|
|
m_atlas_size = -1;
|
2015-08-20 00:24:04 +02:00
|
|
|
m_flags = 0;
|
2015-06-18 01:33:49 +02:00
|
|
|
m_texture_handle = BGFX_INVALID_HANDLE;
|
|
|
|
}
|
2014-06-16 21:18:15 +02:00
|
|
|
|
|
|
|
|
2015-06-18 01:33:49 +02:00
|
|
|
Texture::~Texture()
|
|
|
|
{
|
|
|
|
ASSERT(isEmpty());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-11-11 21:54:25 +01:00
|
|
|
void Texture::setFlag(uint32 flag, bool value)
|
2015-10-09 01:17:32 +02:00
|
|
|
{
|
2015-11-11 21:54:25 +01:00
|
|
|
uint32 new_flags = m_flags & ~flag;
|
2015-10-09 01:17:32 +02:00
|
|
|
new_flags |= value ? flag : 0;
|
|
|
|
m_flags = new_flags;
|
|
|
|
|
|
|
|
getResourceManager().get(ResourceManager::TEXTURE)->reload(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-11-11 21:54:25 +01:00
|
|
|
void Texture::setFlags(uint32 flags)
|
2015-08-20 00:24:04 +02:00
|
|
|
{
|
|
|
|
if (isReady() && m_flags != flags)
|
|
|
|
{
|
|
|
|
g_log_warning.log("Renderer")
|
|
|
|
<< "Trying to set different flags for texture " << getPath().c_str()
|
|
|
|
<< ". They are ignored.";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_flags = flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-08-14 22:12:51 +02:00
|
|
|
void Texture::destroy()
|
2015-06-18 01:33:49 +02:00
|
|
|
{
|
2015-08-14 22:12:51 +02:00
|
|
|
doUnload();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Texture::create(int w, int h, void* data)
|
|
|
|
{
|
|
|
|
if (data)
|
|
|
|
{
|
2015-11-14 00:25:08 +01:00
|
|
|
m_texture_handle = bgfx::createTexture2D((uint16_t)w,
|
|
|
|
(uint16_t)h,
|
|
|
|
1,
|
|
|
|
bgfx::TextureFormat::RGBA8,
|
|
|
|
m_flags,
|
|
|
|
bgfx::copy(data, w * h * 4));
|
2015-08-14 22:12:51 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_texture_handle =
|
2015-11-14 00:25:08 +01:00
|
|
|
bgfx::createTexture2D((uint16_t)w, (uint16_t)h, 1, bgfx::TextureFormat::RGBA8, m_flags);
|
2015-08-14 22:12:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool isReady = bgfx::isValid(m_texture_handle);
|
2015-10-03 01:14:38 +02:00
|
|
|
onCreated(isReady ? State::READY : State::FAILURE);
|
2015-08-14 22:12:51 +02:00
|
|
|
|
|
|
|
return isReady;
|
2015-06-18 01:33:49 +02:00
|
|
|
}
|
2014-08-06 21:37:03 +02:00
|
|
|
|
2015-07-27 00:42:25 +02:00
|
|
|
|
2015-11-11 21:54:25 +01:00
|
|
|
uint32 Texture::getPixelNearest(int x, int y) const
|
2015-08-27 14:13:55 +02:00
|
|
|
{
|
|
|
|
if (m_data.empty() || x >= m_width || y >= m_height || x < 0 || y < 0 ||
|
|
|
|
getBytesPerPixel() != 4)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-11-11 21:54:25 +01:00
|
|
|
return *(uint32*)&m_data[(x + y * m_width) * 4];
|
2015-08-27 14:13:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-11-11 21:54:25 +01:00
|
|
|
uint32 Texture::getPixel(float x, float y) const
|
2015-06-18 01:33:49 +02:00
|
|
|
{
|
2015-07-27 00:42:25 +02:00
|
|
|
if (m_data.empty() || x >= m_width || y >= m_height || x < 0 || y < 0)
|
2014-09-05 21:58:21 +02:00
|
|
|
{
|
2015-06-18 01:33:49 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2014-09-05 22:54:19 +02:00
|
|
|
|
2015-06-18 01:33:49 +02:00
|
|
|
// http://fastcpp.blogspot.sk/2011/06/bilinear-pixel-interpolation-using-sse.html
|
|
|
|
int px = (int)x;
|
|
|
|
int py = (int)y;
|
2015-11-11 21:54:25 +01:00
|
|
|
const uint32* p0 = (uint32*)&m_data[(px + py * m_width) * 4];
|
2015-07-27 00:42:25 +02:00
|
|
|
|
2015-11-11 21:54:25 +01:00
|
|
|
const uint8* p1 = (uint8*)p0;
|
|
|
|
const uint8* p2 = (uint8*)(p0 + 1);
|
|
|
|
const uint8* p3 = (uint8*)(p0 + m_width);
|
|
|
|
const uint8* p4 = (uint8*)(p0 + 1 + m_width);
|
2015-07-27 00:42:25 +02:00
|
|
|
|
2015-06-18 01:33:49 +02:00
|
|
|
float fx = x - px;
|
|
|
|
float fy = y - py;
|
|
|
|
float fx1 = 1.0f - fx;
|
|
|
|
float fy1 = 1.0f - fy;
|
2015-07-27 00:42:25 +02:00
|
|
|
|
2015-06-18 01:33:49 +02:00
|
|
|
int w1 = (int)(fx1 * fy1 * 256.0f);
|
2015-07-27 00:42:25 +02:00
|
|
|
int w2 = (int)(fx * fy1 * 256.0f);
|
|
|
|
int w3 = (int)(fx1 * fy * 256.0f);
|
|
|
|
int w4 = (int)(fx * fy * 256.0f);
|
|
|
|
|
2015-11-11 21:54:25 +01:00
|
|
|
uint8 res[4];
|
2015-07-27 00:42:25 +02:00
|
|
|
res[0] =
|
2015-11-11 21:54:25 +01:00
|
|
|
(uint8)((p1[0] * w1 + p2[0] * w2 + p3[0] * w3 + p4[0] * w4) >> 8);
|
2015-07-27 00:42:25 +02:00
|
|
|
res[1] =
|
2015-11-11 21:54:25 +01:00
|
|
|
(uint8)((p1[1] * w1 + p2[1] * w2 + p3[1] * w3 + p4[1] * w4) >> 8);
|
2015-07-27 00:42:25 +02:00
|
|
|
res[2] =
|
2015-11-11 21:54:25 +01:00
|
|
|
(uint8)((p1[2] * w1 + p2[2] * w2 + p3[2] * w3 + p4[2] * w4) >> 8);
|
2015-07-27 00:42:25 +02:00
|
|
|
res[3] =
|
2015-11-11 21:54:25 +01:00
|
|
|
(uint8)((p1[3] * w1 + p2[3] * w2 + p3[3] * w3 + p4[3] * w4) >> 8);
|
2015-07-27 00:42:25 +02:00
|
|
|
|
2015-11-11 21:54:25 +01:00
|
|
|
return *(uint32*)res;
|
2015-06-18 01:33:49 +02:00
|
|
|
}
|
2014-09-05 21:58:21 +02:00
|
|
|
|
|
|
|
|
2015-07-27 00:42:25 +02:00
|
|
|
unsigned int Texture::compareTGA(IAllocator& allocator,
|
|
|
|
FS::IFile* file1,
|
|
|
|
FS::IFile* file2,
|
|
|
|
int difference)
|
2015-06-18 01:33:49 +02:00
|
|
|
{
|
|
|
|
TGAHeader header1, header2;
|
|
|
|
file1->read(&header1, sizeof(header1));
|
|
|
|
file2->read(&header2, sizeof(header2));
|
|
|
|
|
2015-07-27 00:42:25 +02:00
|
|
|
if (header1.bitsPerPixel != header2.bitsPerPixel ||
|
|
|
|
header1.width != header2.width || header1.height != header2.height ||
|
|
|
|
header1.dataType != header2.dataType ||
|
|
|
|
header1.imageDescriptor != header2.imageDescriptor)
|
2015-01-19 23:02:55 +01:00
|
|
|
{
|
2015-07-27 00:42:25 +02:00
|
|
|
g_log_error.log("renderer")
|
|
|
|
<< "Trying to compare textures with different formats";
|
2015-06-18 01:33:49 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2015-01-19 23:02:55 +01:00
|
|
|
|
2015-06-18 01:33:49 +02:00
|
|
|
int color_mode = header1.bitsPerPixel / 8;
|
|
|
|
if (header1.dataType != 2)
|
|
|
|
{
|
|
|
|
g_log_error.log("renderer") << "Unsupported texture format";
|
|
|
|
return 0;
|
|
|
|
}
|
2015-01-19 23:02:55 +01:00
|
|
|
|
2015-06-18 01:33:49 +02:00
|
|
|
int different_pixel_count = 0;
|
|
|
|
size_t pixel_count = header1.width * header1.height;
|
2015-11-11 21:54:25 +01:00
|
|
|
uint8* img1 = (uint8*)allocator.allocate(pixel_count * color_mode);
|
|
|
|
uint8* img2 = (uint8*)allocator.allocate(pixel_count * color_mode);
|
2015-01-19 23:02:55 +01:00
|
|
|
|
2015-06-18 01:33:49 +02:00
|
|
|
file1->read(img1, pixel_count * color_mode);
|
|
|
|
file2->read(img2, pixel_count * color_mode);
|
2015-01-19 23:02:55 +01:00
|
|
|
|
2015-06-18 01:33:49 +02:00
|
|
|
for (size_t i = 0; i < pixel_count * color_mode; i += color_mode)
|
|
|
|
{
|
|
|
|
for (int j = 0; j < color_mode; ++j)
|
2015-01-19 23:02:55 +01:00
|
|
|
{
|
2015-06-18 01:33:49 +02:00
|
|
|
if (Math::abs(img1[i + j] - img2[i + j]) > difference)
|
2015-01-29 23:58:30 +01:00
|
|
|
{
|
2015-06-18 01:33:49 +02:00
|
|
|
++different_pixel_count;
|
|
|
|
break;
|
2015-01-29 23:58:30 +01:00
|
|
|
}
|
2015-01-19 23:02:55 +01:00
|
|
|
}
|
2015-06-18 01:33:49 +02:00
|
|
|
}
|
2015-01-19 23:02:55 +01:00
|
|
|
|
2015-06-18 01:33:49 +02:00
|
|
|
allocator.deallocate(img1);
|
|
|
|
allocator.deallocate(img2);
|
2015-01-19 23:02:55 +01:00
|
|
|
|
2015-06-18 01:33:49 +02:00
|
|
|
return different_pixel_count;
|
|
|
|
}
|
2015-01-19 23:02:55 +01:00
|
|
|
|
|
|
|
|
2015-07-27 00:42:25 +02:00
|
|
|
bool Texture::saveTGA(IAllocator& allocator,
|
|
|
|
FS::IFile* file,
|
|
|
|
int width,
|
|
|
|
int height,
|
|
|
|
int bytes_per_pixel,
|
2015-11-11 21:54:25 +01:00
|
|
|
const uint8* image_dest,
|
2015-07-27 00:42:25 +02:00
|
|
|
const Path& path)
|
2015-06-18 01:33:49 +02:00
|
|
|
{
|
|
|
|
if (bytes_per_pixel != 4)
|
2014-08-06 21:37:03 +02:00
|
|
|
{
|
2015-07-27 00:42:25 +02:00
|
|
|
g_log_error.log("renderer")
|
|
|
|
<< "Texture " << path.c_str()
|
|
|
|
<< " could not be saved, unsupported TGA format";
|
2015-06-18 01:33:49 +02:00
|
|
|
return false;
|
|
|
|
}
|
2014-06-16 21:18:15 +02:00
|
|
|
|
2015-11-11 21:54:25 +01:00
|
|
|
uint8* data = (uint8*)allocator.allocate(width * height * 4);
|
2014-08-06 21:37:03 +02:00
|
|
|
|
2015-06-18 01:33:49 +02:00
|
|
|
TGAHeader header;
|
2015-11-12 18:30:14 +01:00
|
|
|
setMemory(&header, 0, sizeof(header));
|
2015-06-18 01:33:49 +02:00
|
|
|
header.bitsPerPixel = (char)(bytes_per_pixel * 8);
|
|
|
|
header.height = (short)height;
|
|
|
|
header.width = (short)width;
|
|
|
|
header.dataType = 2;
|
2014-08-06 21:37:03 +02:00
|
|
|
|
2015-06-18 01:33:49 +02:00
|
|
|
file->write(&header, sizeof(header));
|
2014-08-06 21:37:03 +02:00
|
|
|
|
2015-06-18 01:33:49 +02:00
|
|
|
for (long y = 0; y < header.height; y++)
|
|
|
|
{
|
|
|
|
long read_index = y * header.width * 4;
|
2015-07-27 00:42:25 +02:00
|
|
|
long write_index = ((header.imageDescriptor & 32) != 0)
|
|
|
|
? read_index
|
|
|
|
: y * header.width * 4;
|
2015-06-18 01:33:49 +02:00
|
|
|
for (long x = 0; x < header.width; x++)
|
2014-08-06 21:37:03 +02:00
|
|
|
{
|
2015-06-18 01:33:49 +02:00
|
|
|
data[write_index + 0] = image_dest[write_index + 2];
|
|
|
|
data[write_index + 1] = image_dest[write_index + 1];
|
|
|
|
data[write_index + 2] = image_dest[write_index + 0];
|
|
|
|
data[write_index + 3] = image_dest[write_index + 3];
|
|
|
|
write_index += 4;
|
2014-08-06 21:37:03 +02:00
|
|
|
}
|
2015-06-18 01:33:49 +02:00
|
|
|
}
|
2014-08-06 21:37:03 +02:00
|
|
|
|
2015-06-18 01:33:49 +02:00
|
|
|
file->write(data, width * height * 4);
|
2015-01-03 12:13:13 +01:00
|
|
|
|
2015-06-18 01:33:49 +02:00
|
|
|
allocator.deallocate(data);
|
2015-01-03 12:13:13 +01:00
|
|
|
|
2015-06-18 01:33:49 +02:00
|
|
|
return true;
|
|
|
|
}
|
2015-01-03 12:13:13 +01:00
|
|
|
|
|
|
|
|
2015-06-18 01:33:49 +02:00
|
|
|
void Texture::saveTGA()
|
|
|
|
{
|
|
|
|
if (m_data.empty())
|
2015-01-03 12:13:13 +01:00
|
|
|
{
|
2015-07-27 00:42:25 +02:00
|
|
|
g_log_error.log("renderer")
|
|
|
|
<< "Texture " << getPath().c_str()
|
|
|
|
<< " could not be saved, no data was loaded";
|
2015-06-18 01:33:49 +02:00
|
|
|
return;
|
|
|
|
}
|
2015-01-03 12:13:13 +01:00
|
|
|
|
2015-06-18 01:33:49 +02:00
|
|
|
FS::FileSystem& fs = m_resource_manager.getFileSystem();
|
2015-08-02 15:36:52 +02:00
|
|
|
FS::IFile* file = fs.open(fs.getDiskDevice(),
|
|
|
|
getPath().c_str(),
|
|
|
|
FS::Mode::OPEN_OR_CREATE | FS::Mode::WRITE);
|
2015-01-03 12:13:13 +01:00
|
|
|
|
2015-06-18 01:33:49 +02:00
|
|
|
saveTGA(m_allocator, file, m_width, m_height, m_BPP, &m_data[0], getPath());
|
2015-01-03 12:13:13 +01:00
|
|
|
|
2015-08-03 09:19:05 +02:00
|
|
|
fs.close(*file);
|
2015-06-18 01:33:49 +02:00
|
|
|
}
|
2014-08-06 21:37:03 +02:00
|
|
|
|
|
|
|
|
|
|
|
void Texture::save()
|
2014-06-16 21:18:15 +02:00
|
|
|
{
|
2014-08-06 21:37:03 +02:00
|
|
|
char ext[5];
|
|
|
|
ext[0] = 0;
|
|
|
|
PathUtils::getExtension(ext, 5, getPath().c_str());
|
2015-11-12 17:54:02 +01:00
|
|
|
if (compareString(ext, "raw") == 0 && m_BPP == 2)
|
2014-08-06 21:37:03 +02:00
|
|
|
{
|
|
|
|
FS::FileSystem& fs = m_resource_manager.getFileSystem();
|
2015-07-27 00:42:25 +02:00
|
|
|
FS::IFile* file = fs.open(fs.getDefaultDevice(),
|
|
|
|
getPath().c_str(),
|
|
|
|
FS::Mode::OPEN_OR_CREATE | FS::Mode::WRITE);
|
|
|
|
|
2014-08-06 21:37:03 +02:00
|
|
|
file->write(&m_data[0], m_data.size() * sizeof(m_data[0]));
|
2015-08-03 09:19:05 +02:00
|
|
|
fs.close(*file);
|
2014-08-06 21:37:03 +02:00
|
|
|
}
|
2015-11-12 17:54:02 +01:00
|
|
|
else if (compareString(ext, "tga") == 0 && m_BPP == 4)
|
2014-08-06 21:37:03 +02:00
|
|
|
{
|
|
|
|
saveTGA();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-07-27 00:42:25 +02:00
|
|
|
g_log_error.log("renderer") << "Texture " << getPath()
|
|
|
|
<< " can not be saved - unsupported format";
|
2014-08-06 21:37:03 +02:00
|
|
|
}
|
2014-06-16 21:18:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-03 13:24:58 +02:00
|
|
|
void Texture::onDataUpdated(int x, int y, int w, int h)
|
2014-08-02 01:56:37 +02:00
|
|
|
{
|
2015-07-27 00:42:25 +02:00
|
|
|
const bgfx::Memory* mem = nullptr;
|
|
|
|
|
|
|
|
if (m_BPP == 2)
|
|
|
|
{
|
2015-11-11 21:54:25 +01:00
|
|
|
const uint16* src_mem = (const uint16*)&m_data[0];
|
2015-10-03 13:24:58 +02:00
|
|
|
mem = bgfx::alloc(w * h * sizeof(float));
|
2015-07-27 00:42:25 +02:00
|
|
|
float* dst_mem = (float*)mem->data;
|
|
|
|
|
2015-10-03 13:24:58 +02:00
|
|
|
for (int j = 0; j < h; ++j)
|
2015-07-27 00:42:25 +02:00
|
|
|
{
|
2015-10-03 13:24:58 +02:00
|
|
|
for (int i = 0; i < w; ++i)
|
|
|
|
{
|
|
|
|
dst_mem[i + j * w] = src_mem[x + i + (y + j) * m_width] / 65535.0f;
|
|
|
|
}
|
2015-07-27 00:42:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-11-11 21:54:25 +01:00
|
|
|
const uint8* src_mem = (const uint8*)&m_data[0];
|
2015-10-03 13:24:58 +02:00
|
|
|
mem = bgfx::alloc(w * h * m_BPP);
|
2015-11-11 21:54:25 +01:00
|
|
|
uint8* dst_mem = mem->data;
|
2015-10-03 13:24:58 +02:00
|
|
|
|
|
|
|
for (int j = 0; j < h; ++j)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < w; ++i)
|
|
|
|
{
|
2015-11-12 17:32:12 +01:00
|
|
|
copyMemory(&dst_mem[(i + j * w) * m_BPP],
|
2015-10-03 13:24:58 +02:00
|
|
|
&src_mem[(x + i + (y + j) * m_width) * m_BPP],
|
|
|
|
m_BPP);
|
|
|
|
}
|
|
|
|
}
|
2015-07-27 00:42:25 +02:00
|
|
|
}
|
2015-11-14 00:25:08 +01:00
|
|
|
bgfx::updateTexture2D(
|
|
|
|
m_texture_handle, 0, (uint16_t)x, (uint16_t)y, (uint16_t)w, (uint16_t)h, mem);
|
2014-08-02 01:56:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-04 00:39:15 +02:00
|
|
|
bool Texture::loadRaw(FS::IFile& file)
|
|
|
|
{
|
2014-07-27 00:27:01 +02:00
|
|
|
PROFILE_FUNCTION();
|
2014-07-04 00:39:15 +02:00
|
|
|
size_t size = file.size();
|
|
|
|
m_BPP = 2;
|
2014-07-09 19:52:10 +02:00
|
|
|
m_width = (int)sqrt(size / m_BPP);
|
|
|
|
m_height = m_width;
|
2014-07-08 22:10:10 +02:00
|
|
|
|
2014-07-17 22:28:45 +02:00
|
|
|
if (m_data_reference)
|
2014-07-08 22:10:10 +02:00
|
|
|
{
|
2015-09-26 23:56:08 +02:00
|
|
|
m_data.resize((int)size);
|
2014-07-08 22:10:10 +02:00
|
|
|
file.read(&m_data[0], size);
|
|
|
|
}
|
|
|
|
|
2015-11-11 21:54:25 +01:00
|
|
|
const uint16* src_mem = (const uint16*)file.getBuffer();
|
2015-07-27 00:42:25 +02:00
|
|
|
const bgfx::Memory* mem = bgfx::alloc(m_width * m_height * sizeof(float));
|
|
|
|
float* dst_mem = (float*)mem->data;
|
|
|
|
|
|
|
|
for (int i = 0; i < m_width * m_height; ++i)
|
|
|
|
{
|
|
|
|
dst_mem[i] = src_mem[i] / 65535.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_texture_handle = bgfx::createTexture2D(
|
2015-11-14 00:25:08 +01:00
|
|
|
(uint16_t)m_width, (uint16_t)m_height, 1, bgfx::TextureFormat::R32F, m_flags, nullptr);
|
2015-08-17 21:23:56 +02:00
|
|
|
bgfx::updateTexture2D(
|
|
|
|
m_texture_handle,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
2015-11-14 00:25:08 +01:00
|
|
|
(uint16_t)m_width,
|
|
|
|
(uint16_t)m_height,
|
2015-08-17 21:23:56 +02:00
|
|
|
mem);
|
2015-08-20 00:24:04 +02:00
|
|
|
m_depth = 1;
|
2015-06-18 01:33:49 +02:00
|
|
|
return bgfx::isValid(m_texture_handle);
|
2014-07-04 00:39:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 21:18:15 +02:00
|
|
|
bool Texture::loadTGA(FS::IFile& file)
|
|
|
|
{
|
2014-07-27 00:27:01 +02:00
|
|
|
PROFILE_FUNCTION();
|
2014-06-16 21:18:15 +02:00
|
|
|
TGAHeader header;
|
|
|
|
file.read(&header, sizeof(header));
|
|
|
|
|
|
|
|
int color_mode = header.bitsPerPixel / 8;
|
|
|
|
int image_size = header.width * header.height * 4;
|
|
|
|
if (header.dataType != 2)
|
|
|
|
{
|
2015-10-03 01:53:04 +02:00
|
|
|
g_log_error.log("renderer") << "Unsupported texture format " << getPath().c_str();
|
2014-06-16 21:18:15 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (color_mode < 3)
|
|
|
|
{
|
2015-10-03 01:53:04 +02:00
|
|
|
g_log_error.log("renderer") << "Unsupported color mode " << getPath().c_str();
|
2014-06-16 21:18:15 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_width = header.width;
|
|
|
|
m_height = header.height;
|
2015-07-27 00:42:25 +02:00
|
|
|
TextureManager* manager = static_cast<TextureManager*>(
|
|
|
|
getResourceManager().get(ResourceManager::TEXTURE));
|
2014-07-17 22:28:45 +02:00
|
|
|
if (m_data_reference)
|
2014-06-16 21:18:15 +02:00
|
|
|
{
|
|
|
|
m_data.resize(image_size);
|
|
|
|
}
|
2015-11-11 21:54:25 +01:00
|
|
|
uint8* image_dest = m_data_reference
|
2015-07-27 00:42:25 +02:00
|
|
|
? &m_data[0]
|
2015-11-11 21:54:25 +01:00
|
|
|
: (uint8*)manager->getBuffer(image_size);
|
2014-06-16 21:18:15 +02:00
|
|
|
|
|
|
|
// Targa is BGR, swap to RGB, add alpha and flip Y axis
|
|
|
|
for (long y = 0; y < header.height; y++)
|
|
|
|
{
|
|
|
|
long read_index = y * header.width * color_mode;
|
2015-07-27 00:42:25 +02:00
|
|
|
long write_index = ((header.imageDescriptor & 32) != 0)
|
|
|
|
? read_index
|
|
|
|
: y * header.width * 4;
|
2014-06-16 21:18:15 +02:00
|
|
|
for (long x = 0; x < header.width; x++)
|
|
|
|
{
|
2015-11-11 21:54:25 +01:00
|
|
|
file.read(&image_dest[write_index + 2], sizeof(uint8));
|
|
|
|
file.read(&image_dest[write_index + 1], sizeof(uint8));
|
|
|
|
file.read(&image_dest[write_index + 0], sizeof(uint8));
|
2014-06-16 21:18:15 +02:00
|
|
|
if (color_mode == 4)
|
2015-11-11 21:54:25 +01:00
|
|
|
file.read(&image_dest[write_index + 3], sizeof(uint8));
|
2014-06-16 21:18:15 +02:00
|
|
|
else
|
|
|
|
image_dest[write_index + 3] = 255;
|
|
|
|
write_index += 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_BPP = 4;
|
|
|
|
|
2015-07-27 00:42:25 +02:00
|
|
|
m_texture_handle = bgfx::createTexture2D(
|
|
|
|
header.width,
|
|
|
|
header.height,
|
|
|
|
1,
|
|
|
|
bgfx::TextureFormat::RGBA8,
|
2015-08-20 00:24:04 +02:00
|
|
|
m_flags,
|
2015-08-17 21:23:56 +02:00
|
|
|
0);
|
|
|
|
bgfx::updateTexture2D(
|
|
|
|
m_texture_handle,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
header.width,
|
|
|
|
header.height,
|
2015-07-27 00:42:25 +02:00
|
|
|
bgfx::copy(image_dest, header.width * header.height * 4));
|
2015-08-20 00:24:04 +02:00
|
|
|
m_depth = 1;
|
2015-06-18 01:33:49 +02:00
|
|
|
return bgfx::isValid(m_texture_handle);
|
2014-06-16 21:18:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-17 22:28:45 +02:00
|
|
|
void Texture::addDataReference()
|
2014-07-17 22:08:28 +02:00
|
|
|
{
|
2014-07-17 22:28:45 +02:00
|
|
|
++m_data_reference;
|
2015-06-01 23:35:57 +02:00
|
|
|
if (m_data_reference == 1 && isReady())
|
|
|
|
{
|
|
|
|
m_resource_manager.get(ResourceManager::TEXTURE)->reload(*this);
|
|
|
|
}
|
2014-07-17 22:28:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Texture::removeDataReference()
|
|
|
|
{
|
|
|
|
--m_data_reference;
|
|
|
|
if (m_data_reference == 0)
|
2014-07-17 22:08:28 +02:00
|
|
|
{
|
|
|
|
m_data.clear();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-16 21:18:15 +02:00
|
|
|
bool Texture::loadDDS(FS::IFile& file)
|
|
|
|
{
|
2015-07-15 20:31:40 +02:00
|
|
|
bgfx::TextureInfo info;
|
2015-08-20 00:24:04 +02:00
|
|
|
m_texture_handle =
|
2015-11-11 21:54:25 +01:00
|
|
|
bgfx::createTexture(bgfx::copy(file.getBuffer(), (uint32)file.size()),
|
2015-08-20 00:24:04 +02:00
|
|
|
m_flags,
|
|
|
|
0,
|
|
|
|
&info);
|
2015-07-15 20:31:40 +02:00
|
|
|
m_BPP = -1;
|
|
|
|
m_width = info.width;
|
|
|
|
m_height = info.height;
|
2015-08-20 00:24:04 +02:00
|
|
|
m_depth = info.depth;
|
2015-06-18 01:33:49 +02:00
|
|
|
return bgfx::isValid(m_texture_handle);
|
2014-06-16 21:18:15 +02:00
|
|
|
}
|
|
|
|
|
2015-06-18 01:33:49 +02:00
|
|
|
|
2015-10-03 01:14:38 +02:00
|
|
|
bool Texture::load(FS::IFile& file)
|
2014-06-16 21:18:15 +02:00
|
|
|
{
|
2014-07-27 00:27:01 +02:00
|
|
|
PROFILE_FUNCTION();
|
2015-10-03 01:14:38 +02:00
|
|
|
|
2015-10-03 01:53:04 +02:00
|
|
|
const char* path = getPath().c_str();
|
|
|
|
size_t len = getPath().length();
|
2015-10-03 01:14:38 +02:00
|
|
|
bool loaded = false;
|
2015-11-12 17:54:02 +01:00
|
|
|
if (len > 3 && compareString(path + len - 4, ".dds") == 0)
|
2014-06-16 21:18:15 +02:00
|
|
|
{
|
2015-10-03 01:14:38 +02:00
|
|
|
loaded = loadDDS(file);
|
|
|
|
}
|
2015-11-12 17:54:02 +01:00
|
|
|
else if (len > 3 && compareString(path + len - 4, ".raw") == 0)
|
2015-10-03 01:14:38 +02:00
|
|
|
{
|
|
|
|
loaded = loadRaw(file);
|
2014-06-16 21:18:15 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-10-03 01:14:38 +02:00
|
|
|
loaded = loadTGA(file);
|
|
|
|
}
|
|
|
|
if (!loaded)
|
|
|
|
{
|
2015-10-03 01:53:04 +02:00
|
|
|
g_log_warning.log("renderer") << "Error loading texture " << getPath().c_str();
|
2015-10-03 01:14:38 +02:00
|
|
|
return false;
|
2014-06-16 21:18:15 +02:00
|
|
|
}
|
2015-10-03 01:14:38 +02:00
|
|
|
|
|
|
|
m_size = file.size();
|
|
|
|
return true;
|
2014-06-16 21:18:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-10-03 01:14:38 +02:00
|
|
|
void Texture::unload(void)
|
2014-06-16 21:18:15 +02:00
|
|
|
{
|
2015-07-07 08:38:40 +02:00
|
|
|
if (bgfx::isValid(m_texture_handle))
|
|
|
|
{
|
|
|
|
bgfx::destroyTexture(m_texture_handle);
|
2015-07-15 20:31:40 +02:00
|
|
|
m_texture_handle = BGFX_INVALID_HANDLE;
|
2015-07-07 08:38:40 +02:00
|
|
|
}
|
2015-06-18 01:33:49 +02:00
|
|
|
m_data.clear();
|
2014-06-16 21:18:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // ~namespace Lumix
|