efl/src/modules/evas/engines/direct3d/evas_direct3d_object_image.cpp

321 lines
9.2 KiB
C++

//#define ENABLE_LOG_PRINTF
#include <string.h>
#include <d3dx9.h>
#include "evas_direct3d_object_image.h"
#include "evas_direct3d_image_cache.h"
#include "evas_direct3d_device.h"
#include "evas_direct3d_shader_pack.h"
#include "evas_direct3d_vertex_buffer_cache.h"
TArray<D3DObjectImage *> D3DObjectImage::_cache;
bool D3DObjectImage::_cache_enabled = false;
D3DObjectImage::D3DObjectImage()
{
_x = _y = _w = _h = 0;
_sx = _sy = _sw = _sh = 0;
_u = _v = _du = _dv = 0;
_image_id = -1;
_width = _height = 0;
_source[0] = 0;
_color = 0xffffffff;
_cache_i = 0;
_border = D3DXVECTOR4(0, 0, 0, 0);
_uvborder = D3DXVECTOR4(0, 0, 0, 0);
_with_border = false;
_dirty = false;
_image_data_updated = false;
}
D3DObjectImage::~D3DObjectImage()
{
D3DImageCache::Current()->RemoveImageUser(_image_id);
}
void D3DObjectImage::CopyTo(D3DObjectImage *image)
{
assert(image != NULL);
image->_u = _u;
image->_v = _v;
image->_du = _du;
image->_dv = _dv;
image->_image_id = _image_id;
image->_width = _width;
image->_height = _height;
CopyMemory(image->_source, _source, sizeof(_source));
D3DImageCache::Current()->AddImageUser(image->_image_id);
}
void D3DObjectImage::BeginCache()
{
_cache.Allocate(0);
_cache_enabled = true;
}
void D3DObjectImage::EndCache(D3DDevice *d3d)
{
if (!_cache_enabled || _cache.Length() == 0)
return;
D3DShaderPack::Current()->SetVDecl(d3d, D3DShaderPack::VDECL_XYUVC);
D3DShaderPack::Current()->SetVS(d3d, D3DShaderPack::VS_COPY_UV_COLOR);
D3DShaderPack::Current()->SetPS(d3d, D3DShaderPack::PS_TEX_COLOR_FILTER);
static TArray<Vertex> sorted;
static TArray<GroupDesc> groups;
sorted.Allocate(0);
groups.Allocate(0);
bool found = true;
while (found)
{
found = false;
int cur_id = -1;
int num = 0;
for (int i = 0; i < _cache.Length(); i++)
{
// We have processed this
if (_cache[i]->_image_id < 0)
continue;
found = true;
if (cur_id < 0)
cur_id = _cache[i]->_image_id;
if (_cache[i]->_image_id == cur_id)
{
if (!_cache[i]->_with_border)
{
Vertex *data = _cache[i]->MakeData();
sorted.Add(data[0]);
sorted.Add(data[1]);
sorted.Add(data[2]);
sorted.Add(data[3]);
sorted.Add(data[4]);
sorted.Add(data[5]);
_cache[i]->_image_id = -_cache[i]->_image_id - 1;
num++;
}
else
{
Vertex *data = _cache[i]->MakeDataBorder();
int last_len = sorted.Length();
sorted.Allocate(last_len + 6 * 9);
CopyMemory(&sorted[last_len], data, sizeof(Vertex) * 6 * 9);
_cache[i]->_image_id = -_cache[i]->_image_id - 1;
num += 9;
}
}
}
if (num > 0)
{
GroupDesc gd = {num, cur_id};
groups.Add(gd);
}
}
// Restore ids
for (int i = 0; i < _cache.Length(); i++)
_cache[i]->_image_id = -_cache[i]->_image_id - 1;
D3DVertexBufferCache::CacheEntryInfo ce_info;
if (!D3DVertexBufferCache::Current()->InitBuffer(d3d, (BYTE *)sorted.Data(),
sorted.Length() * sizeof(Vertex), ce_info))
{
return;
}
D3DVertexBufferCache::Current()->SelectBufferToDevice(d3d, ce_info.id, sizeof(Vertex));
HRESULT hr;
for (int i = 0, cur = 0; i < groups.Length(); i++)
{
if (FAILED(hr = D3DImageCache::Current()->SelectImageToDevice(d3d, groups[i].id)))
{
Log("Failed to select texture: %X", (DWORD)hr);
}
// d3d->GetDevice()->DrawPrimitiveUP(D3DPT_TRIANGLELIST, groups[i].num * 2,
// &sorted[cur], sizeof(Vertex));
d3d->GetDevice()->DrawPrimitive(D3DPT_TRIANGLELIST, cur, groups[i].num * 2);
cur += groups[i].num * 6;
}
DBG("Image cache drawn: %d items, %d groups", _cache.Length(), groups.Length());
_cache_enabled = false;
}
void D3DObjectImage::Draw(D3DDevice *d3d)
{
_dirty = false;
DBG("Image draw: (%.3f, %.3f, %.3f, %.3f)", _x, _y, _w, _h);
if (_cache_enabled)
{
_cache.Add(this);
_cache_i = _cache.Length() - 1;
return;
}
D3DShaderPack::Current()->SetVDecl(d3d, D3DShaderPack::VDECL_XYUVC);
D3DShaderPack::Current()->SetVS(d3d, D3DShaderPack::VS_COPY_UV_COLOR);
D3DShaderPack::Current()->SetPS(d3d, D3DShaderPack::PS_TEX_COLOR_FILTER);
D3DImageCache::Current()->SelectImageToDevice(d3d, _image_id);
if (!_with_border)
d3d->GetDevice()->DrawPrimitiveUP(D3DPT_TRIANGLELIST, 2, MakeData(), sizeof(Vertex));
else
d3d->GetDevice()->DrawPrimitiveUP(D3DPT_TRIANGLELIST, 18, MakeDataBorder(), sizeof(Vertex));
}
void D3DObjectImage::Init(FLOAT u, FLOAT v, FLOAT du, FLOAT dv,
int image_id, int width, int height, const char *source)
{
_u = u;
_v = v;
_du = du;
_dv = dv;
_image_id = image_id;
_width = width;
_height = height;
#ifdef __MINGW32__
strncpy(_source, source, sizeof(_source) - 1);
#else
strncpy_s(_source, sizeof(_source), source, sizeof(_source) - 1);
#endif // ! __MINGW32__
}
void D3DObjectImage::Setup(FLOAT x, FLOAT y, FLOAT w, FLOAT h,
int sx, int sy, int sw, int sh)
{
if (!_dirty)
{
_x = 1.f;
_y = -1.f;
_w = _h = 0.f;
_sx = _sy = 1.f;
_sw = _sh = 0.f;
}
if (!_with_border)
{
_x = x;
_y = y;
_w = w;
_h = h;
_sx = FLOAT(sx) / FLOAT(_width);
_sy = FLOAT(sy) / FLOAT(_height);
_sw = FLOAT(sw) / FLOAT(_width);
_sh = FLOAT(sh) / FLOAT(_height);
}
else
{
_x = min(_x, x);
_y = max(_y, y);
_w += w / 3;
_h += h / 3;
_sx = min(_sx, FLOAT(sx) / FLOAT(_width));
_sy = min(_sy, FLOAT(sy) / FLOAT(_height));
_sw += FLOAT(sw) / (3.f * FLOAT(_width));
_sh += FLOAT(sh) / (3.f * FLOAT(_height));
}
_dirty = true;
}
void D3DObjectImage::SetupColorFilter(DWORD color)
{
//_color = ((a & 0xff) << 24) | ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff);
_color = color;
}
D3DObjectImage::Vertex *D3DObjectImage::MakeData()
{
//FLOAT z = (FLOAT(_cache_i) + 0.5f) / _cache.Length();
Vertex data[6] = {
{_x, _y, _u + _sx * _du, _v + _sy * _dv, _color},
{_x + _w, _y, _u + (_sx + _sw) * _du, _v + _sy * _dv, _color},
{_x, _y + _h, _u + _sx * _du, _v + (_sy + _sh) * _dv, _color},
{_x, _y + _h, _u + _sx * _du, _v + (_sy + _sh) * _dv, _color},
{_x + _w, _y, _u + (_sx + _sw) * _du, _v + _sy * _dv, _color},
{_x + _w, _y + _h, _u + (_sx + _sw) * _du, _v + (_sy + _sh) * _dv, _color}};
CopyMemory(_data, data, sizeof(data));
return _data;
}
D3DObjectImage::Vertex *D3DObjectImage::MakeDataBorder()
{
//FLOAT z = (FLOAT(_cache_i) + 0.5f) / _cache.Length();
if (_border.x + _border.z > _w)
_border.x = _border.z = _w / 2;
if (_border.y + _border.w < _h)
_border.y = _border.w = _h / 2;
FLOAT ul, ut, ur, ub;
ul = _uvborder.x * _du;
ut = _uvborder.y * _dv;
ur = _uvborder.z * _du;
ub = _uvborder.w * _dv;
FLOAT bl, bt, br, bb;
bl = _border.x;
bt = _border.y;
br = _border.z;
bb = _border.w;
const FLOAT half_x = 0.5f * _du / FLOAT(_width);
const FLOAT half_y = 0.5f * _dv / FLOAT(_height);
// Diagonal knots
Vertex data[4] = {
{_x, _y, _u + _sx * _du + half_x, _v + _sy * _dv + half_y, _color},
{_x + bl, _y + bt, _u + ul + _sx * _du, _v + ut + _sy * _dv, _color},
{_x + _w - br, _y + _h - bb, _u - ur + (_sx + _sw) * _du, _v - ub + (_sy + _sh) * _dv, _color},
{_x + _w, _y + _h, _u + (_sx + _sw) * _du - half_x, _v + (_sy + _sh) * _dv - half_y, _color}};
static const int yshift[6] = {0, 0, 1, 1, 0, 1};
static const int xshift[6] = {0, 1, 0, 0, 1, 1};
int vi = 0;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
for (int v = 0; v < 6; v++)
{
_data[vi].x = data[xshift[v] + j].x;
_data[vi].y = data[yshift[v] + i].y;
_data[vi].u = data[xshift[v] + j].u;
_data[vi].v = data[yshift[v] + i].v;
_data[vi].col = data[0].col;
vi++;
}
}
}
return _data;
}
void D3DObjectImage::SetupBorder(const D3DXVECTOR4 &world_border, const D3DXVECTOR4 &pix_border)
{
_border = world_border;
_uvborder = pix_border;
_with_border = (_border.x > 0.0001f || _border.y > 0.0001f ||
_border.z > 0.0001f || _border.w > 0.0001f);
}
bool D3DObjectImage::UpdateImageData(DWORD *image_data)
{
D3DImageCache::CacheEntryInfo info = {_image_id, _width, _height, _u, _v, _du, _dv};
_image_data_updated = false;
return D3DImageCache::Current()->UpdateImageData(info, image_data);
}
DWORD *D3DObjectImage::GetImageData()
{
if (_image_data_updated)
return _image_data.Data();
_image_data_updated = true;
D3DImageCache::CacheEntryInfo info = {_image_id, _width, _height, _u, _v, _du, _dv};
D3DImageCache::Current()->GetImageData(info, _image_data);
return _image_data.Data();
}