* src/modules/engines/direct3d/:

fast direct3d engine written by Dmitriy Mazovka. You rock !

 * m4/evas_check_engine.m:
 * m4/evas_check_loader.m4:
   use m4_popdef for each macro (otherwise, fail if aclocal is too old)

 * src/lib/canvas/evas_font_dir.c:
   include evas_common.h and evas_private.h after Eet.h and Evil.h
   so that EAPI is correctly defined



SVN revision: 38244
This commit is contained in:
Vincent Torri 2008-12-20 13:22:46 +00:00
parent 8b5ff6cb40
commit c989841ab6
34 changed files with 4622 additions and 815 deletions

View File

@ -311,7 +311,7 @@ evas_engine_[]$1[]_libs=""
AC_CHECK_HEADERS([d3d9.h d3dx9.h.h],
[
have_dep="yes"
evas_engine_[]$1[]_libs="-ld3d9 -ld3dx9d"
evas_engine_[]$1[]_libs="-ld3d9 -ld3dx9 -lgdi32"
]
)
@ -630,6 +630,7 @@ fi
AM_CONDITIONAL(BUILD_ENGINE_[]UP, [test "x${have_evas_engine_[]DOWN}" = "xyes"])
m4_popdef([UP], [DOWN])
m4_popdef([UP])
m4_popdef([DOWN])
])

View File

@ -304,7 +304,8 @@ fi
AM_CONDITIONAL(BUILD_LOADER_[]UP, [test "x${have_evas_image_loader_[]DOWN}" = "xyes"])
m4_popdef([UP], [DOWN])
m4_popdef([UP])
m4_popdef([DOWN])
])

View File

@ -7,9 +7,6 @@
# include <Evil.h>
#endif
#include "evas_common.h"
#include "evas_private.h"
#ifdef BUILD_FONT_LOADER_EET
#include <Eet.h>
#endif
@ -18,6 +15,9 @@
#include <fontconfig/fontconfig.h>
#endif
#include "evas_common.h"
#include "evas_private.h"
/* font dir cache */
static Eina_Hash *font_dirs = NULL;
static Eina_List *fonts_cache = NULL;

View File

@ -3,8 +3,6 @@
#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h>
typedef struct _Evas_Engine_Info_Direct3D Evas_Engine_Info_Direct3D;
@ -15,15 +13,18 @@ struct _Evas_Engine_Info_Direct3D
Evas_Engine_Info magic;
struct {
HWND window;
LPDIRECT3D9 object; /* Direct3D object */
LPDIRECT3DDEVICE9 device; /* Direct3D device */
LPD3DXSPRITE sprite; /* Direct3D sprite */
LPDIRECT3DTEXTURE9 texture; /* Direct3D texture */
int depth;
int rotation;
HWND window;
int rotation;
int depth;
int fullscreen : 1;
int layered : 1;
} info;
struct {
unsigned short width;
unsigned short height;
unsigned char *mask;
} *shape;
};

View File

@ -17,11 +17,20 @@ pkgdir = $(libdir)/evas/modules/engines/direct3d/$(MODULE_ARCH)
pkg_LTLIBRARIES = module.la
module_la_SOURCES = \
evas_engine.c \
evas_outbuf.c \
evas_direct3d_buffer.c \
evas_direct3d_main.cpp
evas_direct3d_context.cpp \
evas_direct3d_device.cpp \
evas_direct3d_image_cache.cpp \
evas_direct3d_main.cpp \
evas_direct3d_object.cpp \
evas_direct3d_object_font.cpp \
evas_direct3d_object_image.cpp \
evas_direct3d_object_line.cpp \
evas_direct3d_object_rect.cpp \
evas_direct3d_scene.cpp \
evas_direct3d_shader_pack.cpp \
evas_direct3d_vertex_buffer_cache.cpp
module_la_CXXFLAGS = -fno-rtti -fno-exceptions
module_la_CXXFLAGS = -fno-exceptions
module_la_LIBADD = $(top_builddir)/src/lib/libevas.la @EINA_LIBS@ @evas_engine_direct3d_libs@
module_la_LDFLAGS = -no-undefined -module -avoid-version
module_la_LIBTOOLFLAGS = --tag=disable-static
@ -30,4 +39,18 @@ include_HEADERS = Evas_Engine_Direct3D.h
endif
EXTRA_DIST = evas_engine.h
EXTRA_DIST = \
array.h \
evas_direct3d_context.h \
evas_direct3d_device.h \
evas_direct3d_image_cache.h \
evas_direct3d_object.h \
evas_direct3d_object_font.h \
evas_direct3d_object_image.h \
evas_direct3d_object_line.h \
evas_direct3d_object_rect.h \
evas_direct3d_scene.h \
evas_direct3d_shader_pack.h \
evas_direct3d_vertex_buffer_cache.h \
evas_engine.h \
ref.h

View File

@ -0,0 +1,305 @@
#ifndef __ARRAY_H__
#define __ARRAY_H__
#include "ref.h"
#include <assert.h>
template <class T>
class TArray : virtual public Referenc
{
public:
TArray();
TArray(const TArray<T> &arr)
{
data = NULL;
size = num = 0;
block_size = arr.block_size;
keep_order = arr.keep_order;
//assert(0 && "Direct assignment for arrays is NOT allowed");
// risky probably, but anyway
arr.CopyTo(*this);
}
~TArray();
bool Allocate(int new_num);
bool Resize(int new_size = 0);
bool Add(T &el);
bool Add(const T &el);
inline T &operator[](int i);
inline const T &operator[](int i) const;
inline const TArray<T> &operator =(const TArray<T> &arr)
{
block_size = arr.block_size;
keep_order = arr.keep_order;
//assert(0 && "Direct assignment for arrays is NOT allowed");
// risky probably, but anyway
arr.CopyTo(*this);
return *this;
}
T *Last()
{
if (num > 0)
return &data[num - 1];
return NULL;
}
inline int Length() const
{
return num;
}
inline int Size() const
{
return size;
}
inline int BlockSize() const
{
return block_size;
}
inline T *Data()
{
return data;
}
inline T **DataPtr()
{
return &data;
}
inline const T *Data() const
{
return data;
}
inline void SetKeepOrder(bool enable)
{
keep_order = enable;
}
bool Find(const T &el);
bool Add(TArray<T> &arr);
bool CopyTo(TArray<T> &dest) const;
bool Init(const T *arr, int len);
void Swap(int to, int from);
void Replace(int i);
bool SetBlockSize(int new_size);
void Set(T &el);
void Set(const T &el);
protected:
T *data;
int size;
int num;
int block_size;
// Some operations restricted, order of the elements is fixed
bool keep_order;
};
namespace Array
{
const int default_block_size = 16;
const int max_array_size = 0xffffff;
}
template <class T> TArray<T>::TArray()
: data(NULL), size(0), num(0), block_size(Array::default_block_size), keep_order(false)
{
}
template <class T> TArray<T>::~TArray()
{
if (data != NULL)
Resize();
}
template <class T> bool TArray<T>::Allocate(int new_num)
{
assert(new_num >= 0 && new_num <= Array::max_array_size);
if (new_num > size)
{
if (!Resize(new_num))
return false;
}
num = new_num;
return true;
}
template <class T> bool TArray<T>::Resize(int new_size)
{
assert(new_size >= 0 && new_size <= Array::max_array_size);
if (new_size == 0)
{
delete[] data;
data = NULL;
size = 0;
num = 0;
return true;
}
if (new_size == size)
return true;
T *new_data = new T[new_size];
if (new_data == NULL)
return false;
if (data != NULL && num > 0)
{
//CopyMemory(new_data, data, num * sizeof(T));
for (int i = 0; i < num && i < new_size; i++)
new_data[i] = data[i];
}
delete[] data;
data = new_data;
size = new_size;
return true;
}
template <class T> bool TArray<T>::Add(T &el)
{
if (data == NULL)
Resize(1);
if (num < size)
{
data[num++] = el;
return true;
}
// num >= size
int new_size = size + block_size;
if (!Resize(new_size))
return false;
data[num++] = el;
return true;
}
template <class T> bool TArray<T>::Add(const T &el)
{
if (data == NULL)
Resize(1);
if (num < size)
{
data[num++] = *(T *)&el;
return true;
}
// num >= size
int new_size = size + block_size;
if (!Resize(new_size))
return false;
data[num++] = *(T *)&el;
return true;
}
template <class T> bool TArray<T>::Add(TArray<T> &arr)
{
if (arr.Length() == 0)
return true;
int numf = num;
if (!Allocate(Length() + arr.Length()))
return false;
CopyMemory(&data[numf], arr.Data(), arr.Length() * sizeof(T));
return true;
}
template <class T> T &TArray<T>::operator [](int i)
{
assert(i >= 0 && i < num);
return data[i];
}
template <class T> const T &TArray<T>::operator [](int i) const
{
assert(i >= 0 && i < num);
return data[i];
}
template <class T> bool TArray<T>::SetBlockSize(int new_size)
{
assert(new_size >= 0 && new_size <= Array::max_array_size);
block_size = new_size;
return true;
}
template <class T> void TArray<T>::Set(T &el)
{
for (int i = 0; i < num; i++)
data[i] = el;
}
template <class T> void TArray<T>::Set(const T &el)
{
for (int i = 0; i < num; i++)
data[i] = el;
}
template <class T> bool TArray<T>::CopyTo(TArray<T> &dest) const
{
if (!dest.Resize(size))
return false;
dest.num = 0;
for (int i = 0; i < num; i++)
dest.Add(data[i]);
return true;
}
template <class T> bool TArray<T>::Init(const T *arr, int len)
{
assert(arr != NULL);
if (!Resize(len))
return false;
num = 0;
for (int i = 0; i < len; i++)
Add((T)arr[i]);
return true;
}
template <class T> void TArray<T>::Swap(int to, int from)
{
assert(to >= 0 && to < num && from >= 0 && from < num);
if (keep_order)
return;
T t = data[to];
data[to] = data[from];
data[from] = t;
}
template <class T> void TArray<T>::Replace(int i)
{
assert(i >= 0 && i < num);
if (keep_order)
return;
if (num >= 1)
{
data[i] = data[num - 1];
num--;
}
}
// operator == for type T should be defined
template <class T> bool TArray<T>::Find(const T &el)
{
for (int i = 0; i < num; i++)
{
if (data[i] == el)
return true;
}
return false;
}
#endif // __ARRAY_H__

View File

@ -1,88 +0,0 @@
#include <string.h>
#include "evas_engine.h"
Direct3D_Output_Buffer *
evas_direct3d_output_buffer_new(int depth,
int width,
int height,
void *data)
{
Direct3D_Output_Buffer *d3dob;
d3dob = calloc(1, sizeof(Direct3D_Output_Buffer));
if (!d3dob) return NULL;
d3dob->image = data;
d3dob->depth = depth;
d3dob->width = width;
d3dob->height = height;
d3dob->pitch = width * (depth >> 3);
if (!d3dob->image)
{
d3dob->image = malloc(d3dob->pitch * height);
if (!d3dob->image)
{
free(d3dob);
return NULL;
}
}
return d3dob;
}
void
evas_direct3d_output_buffer_free(Direct3D_Output_Buffer *d3dob)
{
if (d3dob->image) free(d3dob->image);
free(d3dob);
}
void
evas_direct3d_output_buffer_paste(Direct3D_Output_Buffer *d3dob,
DATA8 *d3d_data,
int d3d_width,
int d3d_height,
int d3d_pitch,
int x,
int y)
{
DATA8 *evas_data;
int width;
int height;
int pitch;
int j;
if ((x >= d3d_width) || (y >= d3d_height))
return;
/* compute the size of the data to copy on the back surface */
width = ((x + d3dob->width) > d3d_width)
? d3d_width - x
: d3dob->width;
height = ((y + d3dob->height) > d3d_height)
? d3d_height - y
: d3dob->height;
pitch = width * (d3dob->depth >> 3);
d3d_data += y * d3d_pitch + x * (d3dob->depth >> 3);
evas_data = (unsigned char *)d3dob->image;
for (j = 0; j < height; j++, evas_data += d3dob->pitch, d3d_data += d3d_pitch)
memcpy(d3d_data, evas_data, pitch);
}
DATA8 *
evas_direct3d_output_buffer_data(Direct3D_Output_Buffer *d3dob,
int *bytes_per_line_ret)
{
if (bytes_per_line_ret) *bytes_per_line_ret = d3dob->pitch;
return d3dob->image;
}
int
evas_direct3d_output_buffer_depth(Direct3D_Output_Buffer *d3dob)
{
return d3dob->depth;
}

View File

@ -0,0 +1,8 @@
#include "evas_direct3d_context.h"
D3DContext::D3DContext()
{
color = 0xff000000;
color_mul = 0xffffffff;
}

View File

@ -0,0 +1,22 @@
#ifndef __EVAS_DIRECT3D_CONTEXT_H__
#define __EVAS_DIRECT3D_CONTEXT_H__
#include "evas_engine.h"
#include "ref.h"
#include "evas_direct3d_object.h"
class D3DContext : virtual public Referenc
{
public:
D3DContext();
public:
DWORD color;
DWORD color_mul;
Ref<D3DObject> font;
};
#endif // __EVAS_DIRECT3D_CONTEXT_H__

View File

@ -0,0 +1,393 @@
//#define ENABLE_LOG_PRINTF
#include "evas_direct3d_device.h"
#include "evas_direct3d_vertex_buffer_cache.h"
D3DDevice::D3DDevice()
{
ResetParams();
}
bool D3DDevice::Init(HWND window, int depth, bool fullscreen)
{
D3DPRESENT_PARAMETERS pp;
D3DDISPLAYMODE dm;
D3DCAPS9 caps;
RECT rect;
DWORD flag;
HRESULT hr;
if (window == NULL)
return false;
Destroy();
_object = Direct3DCreate9(D3D_SDK_VERSION);
if (_object == NULL)
return false;
if (FAILED(hr = _object->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &dm)))
{
Log("GetAdapterDisplayMode failed: %x", hr);
Destroy();
return false;
}
if (FAILED(hr = _object->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps)))
{
Log("GetDeviceCaps failed: %x", hr);
Destroy();
return false;
}
if (!GetClientRect(window, &rect))
{
Log("GetClientRect failed: %x", GetLastError());
Destroy();
return false;
}
if (SUCCEEDED(_object->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
dm.Format, 0, D3DRTYPE_TEXTURE, (depth == 16) ? D3DFMT_R5G6B5 : D3DFMT_A8R8G8B8)))
{
dm.Format = (depth == 16) ? D3DFMT_R5G6B5 : D3DFMT_A8R8G8B8;
}
flag = (caps.VertexProcessingCaps != 0) ?
(D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE) :
D3DCREATE_SOFTWARE_VERTEXPROCESSING;
ZeroMemory(&pp, sizeof(pp));
if (!fullscreen)
{
pp.BackBufferWidth = rect.right - rect.left;
pp.BackBufferHeight = rect.bottom - rect.top;
}
else
{
pp.BackBufferWidth = ::GetSystemMetrics(SM_CXSCREEN);
pp.BackBufferHeight = ::GetSystemMetrics(SM_CYSCREEN);
}
pp.BackBufferFormat = dm.Format;
pp.BackBufferCount = 1;
pp.MultiSampleType = D3DMULTISAMPLE_NONE;
pp.MultiSampleQuality = 0;
pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
pp.hDeviceWindow = window;
pp.Windowed = fullscreen ? FALSE : TRUE;
//pp.EnableAutoDepthStencil = TRUE;
//pp.AutoDepthStencilFormat = D3DFMT_D16;
pp.FullScreen_RefreshRateInHz = 0;
pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
if (FAILED(hr = _object->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
window, flag, &pp, &_device)))
{
Log("CreateDevice failed: %x", hr);
Destroy();
return false;
}
LPDIRECT3DSURFACE9 backbuffer = NULL;
_device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);
backbuffer->GetDesc(&_backbuffer_desc);
backbuffer->Release();
switch (dm.Format) {
case D3DFMT_A8R8G8B8:
case D3DFMT_X8R8G8B8:
_depth = 32;
break;
case D3DFMT_R5G6B5:
_depth = 16;
break;
default:
Log("No supported format found");
Destroy();
return false;
}
//_render_to_texture = false;
_d3dpp = pp;
_device_lost = FALSE;
_scene_rendering = FALSE;
_width = rect.right - rect.left;
_height = rect.bottom - rect.top;
_window = window;
if (FAILED(CreateRenderTarget()))
{
Log("Failed to create render target");
Destroy();
return false;
}
Log("initialized");
return true;
}
bool D3DDevice::Reset(int width, int height, int fullscreen)
{
D3DPRESENT_PARAMETERS pp = _d3dpp;
_d3dpp.BackBufferWidth = (width > 0) ? width : _d3dpp.BackBufferWidth;
_d3dpp.BackBufferHeight = (height > 0) ? height : _d3dpp.BackBufferHeight;
_d3dpp.Windowed = (fullscreen == 1) ? FALSE : ((fullscreen == 0) ? TRUE : _d3dpp.Windowed);
if (FAILED(ResetDevice()))
{
Log("Couldnt restore device");
_d3dpp = pp;
return SUCCEEDED(ResetDevice());
}
_width = _d3dpp.BackBufferWidth;
_height = _d3dpp.BackBufferHeight;
return true;
}
void D3DDevice::Destroy()
{
//if (_render_target != NULL)
//{
// _render_target->Release();
// _render_target = NULL;
//}
if (_render_target_data != NULL)
{
_render_target_data->Release();
_render_target_data = NULL;
}
if (_device != NULL)
{
int num = _device->Release();
assert(num == 0);
}
if (_object != NULL)
_object->Release();
ResetParams();
Log("uninitialized");
}
void D3DDevice::ResetParams()
{
_window = NULL;
_object = NULL;
_device = NULL;
_width = 0;
_height = 0;
_rot = 0;
_depth = 0;
_device_lost = false;
_scene_rendering = false;
ZeroMemory(&_d3dpp, sizeof(_d3dpp));
ZeroMemory(&_backbuffer_desc, sizeof(_backbuffer_desc));
//_render_target = NULL;
_render_target_data = NULL;
_render_data_updated = false;
_render_data.Resize();
//_original_render_target = NULL;
//_render_to_texture = false;
}
HRESULT D3DDevice::RestoreDevice()
{
Log("restore");
assert(_device != NULL);
HRESULT hr = S_OK;
// Test the cooperative level to see if it's okay to render
if (SUCCEEDED(hr = _device->TestCooperativeLevel()))
{
_device_lost = FALSE;
Log("render test ok");
return S_OK;
}
// If the device was lost, do not render until we get it back
if (hr == D3DERR_DEVICELOST)
return E_FAIL;
// Check if the device needs to be reset.
if (hr == D3DERR_DEVICENOTRESET)
{
if (FAILED(hr = ResetDevice()))
return hr;
}
return hr;
}
HRESULT D3DDevice::ResetDevice()
{
Log("reset");
HRESULT hr = S_OK;
_scene_rendering = FALSE;
// Release all video memory objects
// Bad to call such, make better
D3DVertexBufferCache::Current()->Uninitialize();
//if (_render_target != NULL)
//{
// _render_target->Release();
// _render_target = NULL;
//}
if (_render_target_data != NULL)
{
_render_target_data->Release();
_render_target_data = NULL;
}
// Reset the device
if (FAILED(hr = _device->Reset(&_d3dpp)))
{
Log("D3DDevice: Reset of the device failed! Error (%X)", (DWORD)hr);
return hr;
}
// Store render target surface desc
LPDIRECT3DSURFACE9 backbuffer = NULL;
_device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);
if (backbuffer != NULL)
{
backbuffer->GetDesc(&_backbuffer_desc);
backbuffer->Release();
}
// Initialize the app's device-dependent objects
hr = CreateRenderTarget();
if (FAILED(hr))
{
Log("Restoration of device objects failed");
// Invalidate objects
return E_FAIL;
}
Log("Device objects were successfuly restored");
_textures.Set(NULL);
//_device_objects_restored = true;
return S_OK;
}
bool D3DDevice::Begin()
{
if (FAILED(RestoreDevice()))
return false;
//if (_render_to_texture && _render_target != NULL)
//{
// if (FAILED(_device->GetRenderTarget(0, &_original_render_target)))
// return false;
// if (FAILED(_device->SetRenderTarget(0, _render_target)))
// return false;
//}
HRESULT hr;
if (FAILED(hr = _device->BeginScene()))
{
Log("Cannot begin scene: %X", (DWORD)hr);
return false;
}
//static const D3DVIEWPORT9 vp = {0, 0, _width, _height, 0.f, 1.f};
//_device->SetViewport(&vp);
//_device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
//_device->Clear(0, NULL, D3DCLEAR_TARGET /*| D3DCLEAR_ZBUFFER*/, 0xff8080ff, 1.f, 0);
return true;
}
bool D3DDevice::End()
{
_device->EndScene();
_device->Present(NULL, NULL, NULL, NULL);
_render_data_updated = false;
//if (_render_to_texture && _render_target != NULL && _original_render_target != NULL)
//{
// if (FAILED(_device->SetRenderTarget(0, _original_render_target)))
// return false;
//}
return true;
}
TArray<DWORD> &D3DDevice::GetRenderData()
{
if (_render_data_updated)
return _render_data;
_render_data.Allocate(0);
if (_render_target_data == NULL)
return _render_data;
LPDIRECT3DSURFACE9 surf = NULL;
HRESULT hr;
if (FAILED(_device->GetRenderTarget(0, &surf)))
return _render_data;
if (FAILED(hr = _device->GetRenderTargetData(surf, _render_target_data)))
{
Log("Failed to get render target data (%X)", (DWORD)hr);
surf->Release();
return _render_data;
}
D3DLOCKED_RECT lr;
if (FAILED(_render_target_data->LockRect(&lr, NULL, D3DLOCK_READONLY)))
{
surf->Release();
return _render_data;
}
_render_data.Allocate(_width * _height);
for (int i = 0; i < _height; i++)
{
CopyMemory(&_render_data[i * _width], (BYTE *)lr.pBits + i * lr.Pitch,
_width * sizeof(DWORD));
}
_render_target_data->UnlockRect();
_render_data_updated = true;
surf->Release();
return _render_data;
}
HRESULT D3DDevice::SetTexture(DWORD stage, LPDIRECT3DTEXTURE9 tex)
{
if (stage >= 8)
return E_FAIL;
if (_textures.Length() <= (int)stage)
_textures.Allocate(stage + 1);
if (_textures[stage] != tex)
{
_textures[stage] = tex;
return _device->SetTexture(stage, tex);
}
return S_OK;
}
HRESULT D3DDevice::CreateRenderTarget()
{
if (_device == NULL)
return E_FAIL;
//if (_render_target != NULL &&
if (_render_target_data != NULL)
return S_OK;
//if (FAILED(_device->CreateRenderTarget(_width, _height, _backbuffer_desc.Format,
// D3DMULTISAMPLE_NONE, 0, FALSE, &_render_target, NULL)))
//{
// return E_FAIL;
//}
if (FAILED(_device->CreateOffscreenPlainSurface(_backbuffer_desc.Width,
_backbuffer_desc.Height, _backbuffer_desc.Format, D3DPOOL_SYSTEMMEM,
&_render_target_data, NULL)))
{
return E_FAIL;
}
return S_OK;
}

View File

@ -0,0 +1,87 @@
#ifndef __EVAS_DIRECT3D_DEVICE_H__
#define __EVAS_DIRECT3D_DEVICE_H__
#include "evas_engine.h"
#include <assert.h>
#include "ref.h"
#include "array.h"
class D3DDevice : virtual public Referenc
{
public:
D3DDevice();
bool Init(HWND window, int depth, bool fullscreen = false);
bool Reset(int width, int height, int fullscreen);
void Destroy();
bool Begin();
bool End();
inline LPDIRECT3DDEVICE9 GetDevice();
inline int GetWidth();
inline int GetHeight();
inline HWND GetWindow();
inline bool GetFullscreen();
TArray<DWORD> &GetRenderData();
HRESULT SetTexture(DWORD stage, LPDIRECT3DTEXTURE9 tex);
private:
HRESULT RestoreDevice();
HRESULT ResetDevice();
void ResetParams();
HRESULT CreateRenderTarget();
private:
HWND _window;
LPDIRECT3D9 _object;
LPDIRECT3DDEVICE9 _device;
int _width;
int _height;
int _rot;
int _depth;
bool _device_lost;
bool _scene_rendering;
D3DPRESENT_PARAMETERS _d3dpp;
D3DSURFACE_DESC _backbuffer_desc;
//LPDIRECT3DSURFACE9 _render_target;
LPDIRECT3DSURFACE9 _render_target_data;
//LPDIRECT3DSURFACE9 _original_render_target;
//bool _render_to_texture;
TArray<DWORD> _render_data;
bool _render_data_updated;
TArray<LPDIRECT3DTEXTURE9> _textures;
};
LPDIRECT3DDEVICE9 D3DDevice::GetDevice()
{
return _device;
}
int D3DDevice::GetWidth()
{
return _width;
}
int D3DDevice::GetHeight()
{
return _height;
}
HWND D3DDevice::GetWindow()
{
return _window;
}
bool D3DDevice::GetFullscreen()
{
return (_d3dpp.Windowed == 0);
}
#endif // __EVAS_DIRECT3D_DEVICE_H__

View File

@ -0,0 +1,436 @@
#include "evas_direct3d_image_cache.h"
#include "evas_direct3d_device.h"
#include <assert.h>
Ref<D3DImageCache> D3DImageCache::_this;
D3DImageCache::D3DImageCache()
{
_max_width = 512;
_max_height = 512;
_margin = 0;
}
D3DImageCache::~D3DImageCache()
{
Uninitialize();
}
D3DImageCache *D3DImageCache::Current()
{
if (_this.IsNull())
_this = new D3DImageCache();
return _this;
}
void D3DImageCache::SetCurrent(D3DImageCache *obj)
{
_this = obj;
}
void D3DImageCache::Uninitialize()
{
for (int i = 0; i < _cache.Length(); i++)
{
// In normal case they all will be NULL
if (_cache[i].texture != NULL)
_cache[i].texture->Release();
}
_cache.Resize();
}
bool D3DImageCache::SelectImageToDevice(D3DDevice *d3d, int id)
{
if (id < 0 || id >= _cache.Length())
return false;
assert(_cache[id].texture != NULL);
return SUCCEEDED(d3d->SetTexture(_cache[id].stage, _cache[id].texture));
}
void D3DImageCache::RemoveImageUser(int id)
{
if (id < 0 || id >= _cache.Length())
return;
assert(_cache[id].texture != NULL);
_cache[id].users--;
if (_cache[id].users == 0)
{
_cache[id].texture->Release();
ZeroMemory(&_cache[id], sizeof(_cache[id]));
}
}
void D3DImageCache::AddImageUser(int id)
{
if (id < 0 || id >= _cache.Length())
return;
assert(_cache[id].texture != NULL);
_cache[id].users++;
}
bool D3DImageCache::InsertImage(D3DDevice *d3d, DWORD *data, int w, int h, CacheEntryInfo &info)
{
CacheEntry *ce = NULL;
int id = -1;
for (int i = 0; i < _cache.Length(); i++)
{
if (!_cache[i].locked && RequestInsert(_cache[i], w, h))
{
ce = &_cache[i];
id = i;
break;
}
}
if (ce == NULL)
{
CacheEntry new_entry;
if (!CreateEntry(d3d, new_entry, w, h))
return false;
for (id = 0; id < _cache.Length(); id++)
{
if (_cache[id].texture == NULL)
break;
}
if (id < _cache.Length())
{
_cache[id] = new_entry;
ce = &_cache[id];
}
else
{
_cache.Add(new_entry);
ce = _cache.Last();
id = _cache.Length() - 1;
}
}
assert(ce != NULL && ce->texture != NULL);
if (!InsertData(*ce, data, w, h))
return false;
info.id = id;
info.u = FLOAT(ce->cur_x) / FLOAT(ce->width);
info.v = FLOAT(ce->cur_y) / FLOAT(ce->height);
info.du = FLOAT(w) / FLOAT(ce->width);
info.dv = FLOAT(h) / FLOAT(ce->height);
info.width = w;
info.height = h;
UpdateInsert(*ce, w, h);
return true;
}
bool D3DImageCache::InsertImage(D3DDevice *d3d, int id, DWORD *data, int w, int h, CacheEntryInfo &info)
{
if (id < 0 || id >= _cache.Length())
return false;
assert(_cache[id].texture != NULL);
CacheEntry *ce = &_cache[id];
if (!RequestInsert(*ce, w, h))
return false;
if (!InsertData(*ce, data, w, h))
return false;
info.id = id;
info.u = FLOAT(ce->cur_x) / FLOAT(ce->width);
info.v = FLOAT(ce->cur_y) / FLOAT(ce->height);
info.du = FLOAT(w) / FLOAT(ce->width);
info.dv = FLOAT(h) / FLOAT(ce->height);
info.width = w;
info.height = h;
UpdateInsert(*ce, w, h);
return true;
}
bool D3DImageCache::CreateImage(D3DDevice *d3d, int w, int h, bool locked, CacheEntryInfo &info)
{
int id;
CacheEntry new_entry;
CacheEntry *ce = NULL;
if (!CreateEntry(d3d, new_entry, w, h, true))
return false;
for (id = 0; id < _cache.Length(); id++)
{
if (_cache[id].texture == NULL)
break;
}
if (id < _cache.Length())
{
_cache[id] = new_entry;
ce = &_cache[id];
}
else
{
_cache.Add(new_entry);
ce = _cache.Last();
id = _cache.Length() - 1;
}
assert(ce != NULL && ce->texture != NULL);
// Fill with zero
if (!InsertData(*ce, NULL, w, h))
return false;
info.id = id;
info.u = 0;
info.v = 0;
info.du = 1;
info.dv = 1;
info.width = w;
info.height = h;
UpdateInsert(*ce, 0, 0);
ce->locked = locked;
return true;
}
bool D3DImageCache::ResizeImage(D3DDevice *d3d, int nw, int nh, int id)
{
if (id < 0 || id >= _cache.Length())
return false;
assert(_cache[id].texture != NULL);
CacheEntry *ce = &_cache[id];
if (ce->width == nw && ce->height == nh)
return true;
LPDIRECT3DTEXTURE9 tex = NULL;
HRESULT hr;
if (FAILED(hr = d3d->GetDevice()->CreateTexture(nw, nh, 0, 0, D3DFMT_A8R8G8B8,
D3DPOOL_MANAGED, &tex, NULL)))
{
Log("Failed to create texture: %X", hr);
return false;
}
assert(tex != NULL);
ce->texture->Release();
ce->texture = tex;
ce->width = nw;
ce->height = nh;
return true;
}
bool D3DImageCache::RequestInsert(CacheEntry &entry, int w, int h)
{
// If we already have large image entry
if (entry.width > _max_width || entry.height > _max_height)
return false;
// If requested size does not fit into this entry at all
if (entry.height - entry.cur_h < h + _margin * 2 || entry.width < w + _margin * 2)
return false;
// If requested size does not fit into the current line of the entry
if (entry.width - entry.cur_x < w + _margin * 2)
{
entry.cur_y = entry.cur_h + _margin;
entry.cur_x = _margin;
return true;
}
entry.cur_x += _margin;
return true;
}
bool D3DImageCache::CreateEntry(D3DDevice *d3d, CacheEntry &entry, int w, int h, bool exact_size)
{
int width = exact_size ? w : max(_max_width, w);
int height = exact_size ? h : max(_max_height, h);
HRESULT hr;
if (FAILED(hr = d3d->GetDevice()->CreateTexture(width, height, 0, 0, D3DFMT_A8R8G8B8,
D3DPOOL_MANAGED, &entry.texture, NULL)))
{
Log("Failed to create texture: %X", hr);
return false;
}
entry.cur_x = entry.cur_y = entry.cur_h = 0;
entry.width = width;
entry.height = height;
entry.users = 0;
entry.locked = false;
entry.stage = 0;
return true;
}
bool D3DImageCache::InsertData(CacheEntry &entry, DWORD *data, int w, int h)
{
if (entry.texture == NULL)
return false;
RECT rc = {entry.cur_x, entry.cur_y, entry.cur_x + w, entry.cur_y + h};
D3DLOCKED_RECT lr;
if (FAILED(entry.texture->LockRect(0, &lr, &rc, 0)))
{
Log("Failed to lock texture");
return false;
}
if (data != NULL)
{
for (int i = 0; i < h; i++)
CopyMemory(((BYTE *)lr.pBits) + i * lr.Pitch, data + i * w, sizeof(DWORD) * w);
}
else
{
for (int i = 0; i < h; i++)
ZeroMemory(((BYTE *)lr.pBits) + i * lr.Pitch, sizeof(DWORD) * w);
}
if (FAILED(entry.texture->UnlockRect(0)))
{
Log("Failed to unlock texture");
return false;
}
return true;
}
bool D3DImageCache::RetrieveData(CacheEntry &entry, DWORD *data, int w, int h)
{
if (entry.texture == NULL || data == NULL)
return false;
RECT rc = {entry.cur_x, entry.cur_y, entry.cur_x + w, entry.cur_y + h};
D3DLOCKED_RECT lr;
if (FAILED(entry.texture->LockRect(0, &lr, &rc, D3DLOCK_READONLY)))
{
Log("Failed to lock texture");
return false;
}
for (int i = 0; i < h; i++)
CopyMemory(data + i * w, ((BYTE *)lr.pBits) + i * lr.Pitch, sizeof(DWORD) * w);
if (FAILED(entry.texture->UnlockRect(0)))
{
Log("Failed to unlock texture");
return false;
}
return true;
}
void D3DImageCache::UpdateInsert(CacheEntry &entry, int w, int h)
{
entry.cur_h = max(entry.cur_h, entry.cur_y + h + _margin);
entry.cur_x += w + _margin;
entry.users++;
}
bool D3DImageCache::UpdateImageData(CacheEntryInfo &info, DWORD *data)
{
assert(data != NULL);
if (info.id < 0 || info.id >= _cache.Length())
return false;
CacheEntry ce_copy = _cache[info.id];
ce_copy.cur_x = int(info.u * FLOAT(ce_copy.width));
ce_copy.cur_y = int(info.v * FLOAT(ce_copy.height));
return InsertData(ce_copy, data, info.width, info.height);
}
bool D3DImageCache::UpdateImageDataWithDirtyInfo(CacheEntryInfo &info, DWORD *data, POINT *dirty)
{
if (info.id < 0 || info.id >= _cache.Length())
return false;
CacheEntry &entry = _cache[info.id];
if (entry.texture == NULL)
return false;
RECT rc = {0, 0, entry.width, entry.height};
D3DLOCKED_RECT lr;
if (FAILED(entry.texture->LockRect(0, &lr, &rc, 0)))
{
Log("Failed to lock texture");
return false;
}
if (data != NULL)
{
for (int i = 0; i < rc.bottom; i++)
{
if (dirty[i].x < 0 && dirty[i].y < 0)
continue;
if (dirty[i].x >= 0 && dirty[i].y >= 0)
{
CopyMemory(((BYTE *)lr.pBits) + i * lr.Pitch + dirty[i].x * 4,
data + i * rc.right + dirty[i].x, sizeof(DWORD) * (dirty[i].y - dirty[i].x + 1));
dirty[i].y = -dirty[i].y;
}
else if (dirty[i].x >= 0 && dirty[i].y < 0)
{
ZeroMemory(((BYTE *)lr.pBits) + i * lr.Pitch + dirty[i].x * 4,
sizeof(DWORD) * (-dirty[i].y - dirty[i].x + 1));
dirty[i].x = -dirty[i].x;
}
}
}
else
{
for (int i = 0; i < rc.bottom; i++)
{
if (dirty[i].x < 0 || dirty[i].y < 0)
continue;
ZeroMemory(((BYTE *)lr.pBits) + i * lr.Pitch + dirty[i].x * 4,
sizeof(DWORD) * (dirty[i].y - dirty[i].x + 1));
}
}
if (FAILED(entry.texture->UnlockRect(0)))
{
Log("Failed to unlock texture");
return false;
}
return true;
}
bool D3DImageCache::UpdateImageDataDiscard(CacheEntryInfo &info, DWORD *data)
{
assert(data != NULL);
if (info.id < 0 || info.id >= _cache.Length())
return false;
CacheEntry &entry = _cache[info.id];
if (entry.texture == NULL)
return false;
RECT rc = {0, 0, entry.width, entry.height};
D3DLOCKED_RECT lr;
if (FAILED(entry.texture->LockRect(0, &lr, &rc, 0)))
{
Log("Failed to lock texture");
return false;
}
for (int i = 0; i < rc.bottom; i++)
{
CopyMemory(((BYTE *)lr.pBits) + i * lr.Pitch,
data + i * rc.right, sizeof(DWORD) * rc.right);
}
if (FAILED(entry.texture->UnlockRect(0)))
{
Log("Failed to unlock texture");
return false;
}
return true;
}
bool D3DImageCache::GetImageData(CacheEntryInfo &info, TArray<DWORD> &data)
{
if (info.id < 0 || info.id >= _cache.Length())
return false;
CacheEntry ce_copy = _cache[info.id];
ce_copy.cur_x = int(info.u * FLOAT(ce_copy.width));
ce_copy.cur_y = int(info.v * FLOAT(ce_copy.height));
data.Allocate(info.width * info.height);
return RetrieveData(ce_copy, data.Data(), info.width, info.height);
}

View File

@ -0,0 +1,108 @@
#ifndef __EVAS_DIRECT3D_IMAGE_CACHE_H__
#define __EVAS_DIRECT3D_IMAGE_CACHE_H__
#include "evas_engine.h"
#include "ref.h"
#include "array.h"
class D3DDevice;
class D3DImageCache : virtual public Referenc
{
public:
struct CacheEntryInfo
{
int id;
int width, height;
FLOAT u, v;
FLOAT du, dv;
};
public:
~D3DImageCache();
static D3DImageCache *Current();
static void SetCurrent(D3DImageCache *obj);
inline void SetMaxSize(int w, int h);
inline void SetMargin(int margin);
bool InsertImage(D3DDevice *d3d, DWORD *data, int w, int h, CacheEntryInfo &info);
bool InsertImage(D3DDevice *d3d, int id, DWORD *data, int w, int h, CacheEntryInfo &info);
bool CreateImage(D3DDevice *d3d, int w, int h, bool locked, CacheEntryInfo &info);
bool ResizeImage(D3DDevice *d3d, int nw, int nh, int id);
bool SelectImageToDevice(D3DDevice *d3d, int id);
void RemoveImageUser(int id);
void AddImageUser(int id);
bool UpdateImageData(CacheEntryInfo &info, DWORD *data);
bool UpdateImageDataWithDirtyInfo(CacheEntryInfo &info, DWORD *data, POINT *dirty);
bool UpdateImageDataDiscard(CacheEntryInfo &info, DWORD *data);
bool GetImageData(CacheEntryInfo &info, TArray<DWORD> &data);
void Uninitialize();
inline int GetImageWidth(int image_id);
inline int GetImageHeight(int image_id);
inline void SetImageStage(int image_id, int stage);
private:
struct CacheEntry
{
LPDIRECT3DTEXTURE9 texture;
int width;
int height;
int cur_x;
int cur_y;
int cur_h;
int users;
bool locked;
int stage;
};
private:
D3DImageCache();
bool RequestInsert(CacheEntry &entry, int w, int h);
bool CreateEntry(D3DDevice *d3d, CacheEntry &entry, int w, int h, bool exact_size = false);
bool InsertData(CacheEntry &entry, DWORD *data, int w, int h);
bool RetrieveData(CacheEntry &entry, DWORD *data, int w, int h);
void UpdateInsert(CacheEntry &entry, int w, int h);
private:
TArray<CacheEntry> _cache;
int _max_width;
int _max_height;
int _margin;
static Ref<D3DImageCache> _this;
};
void D3DImageCache::SetMaxSize(int w, int h)
{
_max_width = w;
_max_height = h;
}
void D3DImageCache::SetMargin(int margin)
{
_margin = margin;
}
int D3DImageCache::GetImageWidth(int image_id)
{
return _cache[image_id].width;
}
int D3DImageCache::GetImageHeight(int image_id)
{
return _cache[image_id].height;
}
void D3DImageCache::SetImageStage(int image_id, int stage)
{
_cache[image_id].stage = stage;
}
#endif // __EVAS_DIRECT3D_IMAGE_CACHE_H__

View File

@ -1,84 +1,772 @@
// Force the layered windows APIs to be visible.
#define _WIN32_WINNT 0x0500
#include "evas_engine.h"
#include <assert.h>
#include "evas_direct3d_device.h"
#include "evas_direct3d_context.h"
#include "evas_direct3d_shader_pack.h"
#include "evas_direct3d_scene.h"
#include "evas_direct3d_image_cache.h"
#include "evas_direct3d_object_line.h"
#include "evas_direct3d_object_rect.h"
#include "evas_direct3d_object_image.h"
#include "evas_direct3d_vertex_buffer_cache.h"
#include "evas_direct3d_object_font.h"
// Internal structure that joins two types of objects
struct ImagePtr
{
Ref<D3DObjectImage> ref;
RGBA_Image *img;
};
struct DevicePtr
{
Ref<D3DDevice> device;
Ref<D3DScene> scene;
Ref<D3DContext> context;
Ref<D3DImageCache> image_cache;
Ref<D3DShaderPack> shader_pack;
Ref<D3DVertexBufferCache> vb_cache;
int fonts_buffer_image_id;
// Layered windows cannot render D3D in the normal way
bool layered;
// Window shape mask
struct
{
// Width and height may be different from target size
int width;
int height;
// Pointer to external memory location, dont do anything with it
unsigned char *mask;
} shape;
// GDI output target
struct
{
HBITMAP image;
HDC hdc;
BITMAPINFO info;
BYTE *data;
} dib;
};
DevicePtr *SelectDevice(Direct3DDeviceHandler d3d)
{
DevicePtr *dev_ptr = (DevicePtr *)d3d;
D3DImageCache::SetCurrent(dev_ptr->image_cache);
D3DShaderPack::SetCurrent(dev_ptr->shader_pack);
D3DVertexBufferCache::SetCurrent(dev_ptr->vb_cache);
return dev_ptr;
}
void DeleteDIBObjects(DevicePtr *dev_ptr)
{
assert(dev_ptr != NULL);
if (dev_ptr->dib.image != NULL)
DeleteObject(dev_ptr->dib.image);
if (dev_ptr->dib.hdc != NULL)
DeleteDC(dev_ptr->dib.hdc);
ZeroMemory(&dev_ptr->dib, sizeof(dev_ptr->dib));
}
bool CreateDIBObjects(DevicePtr *dev_ptr)
{
assert(dev_ptr != NULL);
if ((dev_ptr->dib.hdc = CreateCompatibleDC(NULL)) == NULL)
{
Log("Failed to create compatible DC");
return false;
}
ZeroMemory(&dev_ptr->dib.info, sizeof(dev_ptr->dib.info));
dev_ptr->dib.info.bmiHeader.biSize = sizeof(dev_ptr->dib.info.bmiHeader);
dev_ptr->dib.info.bmiHeader.biBitCount = 32;
dev_ptr->dib.info.bmiHeader.biWidth = dev_ptr->device->GetWidth();
dev_ptr->dib.info.bmiHeader.biHeight = -dev_ptr->device->GetHeight();
dev_ptr->dib.info.bmiHeader.biCompression = BI_RGB;
dev_ptr->dib.info.bmiHeader.biPlanes = 1;
if ((dev_ptr->dib.image = CreateDIBSection(dev_ptr->dib.hdc, &dev_ptr->dib.info,
DIB_RGB_COLORS, (void **)&dev_ptr->dib.data, NULL, 0)) == NULL)
{
Log("Failed to create dib section");
DeleteDIBObjects(dev_ptr);
return false;
}
assert(dev_ptr->dib.data != NULL);
GdiFlush();
return true;
}
extern "C" {
int
evas_direct3d_masks_get(Outbuf *buf)
Direct3DDeviceHandler evas_direct3d_init(HWND window, int depth, int fullscreen)
{
D3DSURFACE_DESC sd;
Ref<D3DDevice> device = new D3DDevice();
if (!device->Init(window, depth, fullscreen == 1))
return NULL;
if (FAILED(buf->priv.d3d.texture->GetLevelDesc(0, &sd)))
return 0;
D3DImageCache::SetCurrent(NULL);
D3DShaderPack::SetCurrent(NULL);
D3DVertexBufferCache::SetCurrent(NULL);
switch (sd.Format)
{
case D3DFMT_A8R8G8B8:
case D3DFMT_X8R8G8B8:
buf->priv.mask.r = 0x00ff0000;
buf->priv.mask.g = 0x0000ff00;
buf->priv.mask.b = 0x000000ff;
break;
case D3DFMT_R5G6B5:
buf->priv.mask.r = 0xf800;
buf->priv.mask.g = 0x07e0;
buf->priv.mask.b = 0x001f;
break;
default:
return 0;
}
if (!D3DShaderPack::Current()->Initialize(device))
{
Log("Failed to build shader pack");
device->Destroy();
return NULL;
}
return 1;
}
DevicePtr *dev_ptr = new DevicePtr;
ZeroMemory(dev_ptr, sizeof(DevicePtr));
dev_ptr->device = device;
dev_ptr->scene = new D3DScene();
dev_ptr->context = new D3DContext();
dev_ptr->image_cache = D3DImageCache::Current();
dev_ptr->shader_pack = D3DShaderPack::Current();
dev_ptr->vb_cache = D3DVertexBufferCache::Current();
dev_ptr->fonts_buffer_image_id = -1;
void *
evas_direct3d_lock(Outbuf *buf, int *d3d_width, int *d3d_height, int *d3d_pitch)
{
D3DSURFACE_DESC sd;
D3DLOCKED_RECT d3d_rect;
D3DImageCache::CacheEntryInfo info;
if (!D3DImageCache::Current()->CreateImage(device, device->GetWidth(), device->GetHeight(),
true, info))
{
Log("Failed to create fonts image buffer");
return NULL;
}
dev_ptr->fonts_buffer_image_id = info.id;
D3DImageCache::Current()->SetImageStage(info.id, 1);
/* is that call needed / overkill ? */
if (FAILED(buf->priv.d3d.texture->GetLevelDesc(0, &sd)))
return NULL;
if (FAILED(buf->priv.d3d.device->BeginScene()))
return NULL;
if (FAILED(buf->priv.d3d.sprite->Begin(D3DXSPRITE_DO_NOT_ADDREF_TEXTURE)))
{
buf->priv.d3d.device->EndScene();
return NULL;
}
if (FAILED(buf->priv.d3d.texture->LockRect(0, &d3d_rect, NULL, D3DLOCK_DISCARD)))
{
buf->priv.d3d.sprite->End();
buf->priv.d3d.device->EndScene();
return NULL;
}
*d3d_width = sd.Width;
*d3d_height = sd.Height;
*d3d_pitch = d3d_rect.Pitch;
return d3d_rect.pBits;
return (Direct3DDeviceHandler)dev_ptr;
}
void
evas_direct3d_unlock(Outbuf *buf)
evas_direct3d_free(Direct3DDeviceHandler d3d)
{
if (FAILED(buf->priv.d3d.texture->UnlockRect(0)))
return;
DevicePtr *dev_ptr = SelectDevice(d3d);
if (FAILED(buf->priv.d3d.sprite->Draw(buf->priv.d3d.texture,
NULL, NULL, NULL,
D3DCOLOR_ARGB (255, 255, 255, 255))))
return;
if (FAILED(buf->priv.d3d.sprite->End()))
return;
DeleteDIBObjects(dev_ptr);
if (FAILED(buf->priv.d3d.device->EndScene()))
return;
if (FAILED(buf->priv.d3d.device->Present(NULL, NULL, NULL, NULL)))
return;
dev_ptr->context = NULL;
dev_ptr->scene = NULL;
dev_ptr->image_cache = NULL;
dev_ptr->shader_pack = NULL;
D3DShaderPack::Current()->Uninitialize();
D3DImageCache::Current()->Uninitialize();
D3DVertexBufferCache::Current()->Uninitialize();
D3DShaderPack::SetCurrent(NULL);
D3DImageCache::SetCurrent(NULL);
D3DVertexBufferCache::SetCurrent(NULL);
dev_ptr->device = NULL;
delete dev_ptr;
Log("uninitialized");
}
void
evas_direct3d_resize(Direct3DDeviceHandler d3d, int width, int height)
{
DevicePtr *dev_ptr = SelectDevice(d3d);
D3DDevice *device = dev_ptr->device;
if (!device->Reset(width, height, -1))
{
Log("Failed to resize");
return;
}
if (!D3DImageCache::Current()->ResizeImage(device, width, height,
dev_ptr->fonts_buffer_image_id))
{
Log("Failed to resize fonts image buffer");
}
if (dev_ptr->layered)
{
DeleteDIBObjects(dev_ptr);
if (!CreateDIBObjects(dev_ptr))
Log("Failed to create dib objects");
}
}
void
evas_direct3d_set_fullscreen(Direct3DDeviceHandler d3d, int width, int height, int fullscreen)
{
DevicePtr *dev_ptr = SelectDevice(d3d);
D3DDevice *device = dev_ptr->device;
if (width < 0)
width = ::GetSystemMetrics(SM_CXSCREEN);
if (height < 0)
height = ::GetSystemMetrics(SM_CYSCREEN);
if (!device->Reset(width, height, fullscreen))
{
Log("Failed to resize");
return;
}
if (!D3DImageCache::Current()->ResizeImage(device, width, height,
dev_ptr->fonts_buffer_image_id))
{
Log("Failed to resize fonts image buffer");
}
if (fullscreen == 0)
InvalidateRect(HWND_DESKTOP, NULL, TRUE);
}
void
evas_direct3d_set_layered(Direct3DDeviceHandler d3d, int layered,
int mask_width, int mask_height, unsigned char *mask)
{
DevicePtr *dev_ptr = SelectDevice(d3d);
dev_ptr->layered = (layered != 0);
dev_ptr->shape.width = mask_width;
dev_ptr->shape.height = mask_height;
dev_ptr->shape.mask = mask;
if (dev_ptr->layered && dev_ptr->dib.data == NULL)
CreateDIBObjects(dev_ptr);
else if (!dev_ptr->layered)
DeleteDIBObjects(dev_ptr);
}
void
evas_direct3d_context_color_set(Direct3DDeviceHandler d3d, int r, int g, int b, int a)
{
DevicePtr *dev_ptr = SelectDevice(d3d);
dev_ptr->context->color = ((a & 0xff) << 24) | ((r & 0xff) << 16) |
((g & 0xff) << 8) | (b & 0xff);
}
void
evas_direct3d_context_set_multiplier(Direct3DDeviceHandler d3d, int r, int g, int b, int a)
{
DevicePtr *dev_ptr = SelectDevice(d3d);
dev_ptr->context->color_mul = ((a & 0xff) << 24) | ((r & 0xff) << 16) |
((g & 0xff) << 8) | (b & 0xff);
}
void
evas_direct3d_render_all(Direct3DDeviceHandler d3d)
{
Log("render");
assert(d3d != NULL);
DevicePtr *dev_ptr = SelectDevice(d3d);
D3DDevice *device = dev_ptr->device;
D3DScene *scene = dev_ptr->scene;
if (!device->Begin())
return;
device->GetDevice()->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
device->GetDevice()->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
device->GetDevice()->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
//device->GetDevice()->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
//device->GetDevice()->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
D3DObjectLine::BeginCache();
D3DObjectRect::BeginCache();
D3DObjectImage::BeginCache();
scene->DrawAll(device);
D3DObjectLine::EndCache(device);
D3DObjectRect::EndCache(device);
D3DObjectImage::EndCache(device);
D3DObjectFont::EndCache(device);
device->End();
if (dev_ptr->layered && !device->GetFullscreen() && dev_ptr->dib.data != NULL)
{
HDC hdc = GetDC(device->GetWindow());
if (hdc != NULL)
{
POINT dest = {0, 0};
POINT src = {0, 0};
SIZE client = {device->GetWidth(), device->GetHeight()};
BLENDFUNCTION blend_func = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
if (device->GetRenderData().Length() == client.cx * client.cy)
{
CopyMemory(dev_ptr->dib.data, device->GetRenderData().Data(),
sizeof(DWORD) * client.cx * client.cy);
}
for (int i = 0; i < client.cy; i++)
{
for (int j = 0; j < client.cx; j++)
{
int mask_i = int(dev_ptr->shape.height * float(i) / float(client.cy));
int mask_j = int(dev_ptr->shape.width * float(j) / float(client.cx));
if (mask_i < 0)
mask_i = 0;
else if (mask_i >= dev_ptr->shape.height)
mask_i = dev_ptr->shape.height - 1;
if (mask_j < 0)
mask_j = 0;
else if (mask_j >= dev_ptr->shape.width)
mask_j = dev_ptr->shape.width - 1;
BYTE mask_b = dev_ptr->shape.mask[mask_i * dev_ptr->shape.width + mask_j];
float alpha = float(mask_b) / 255.f;
dev_ptr->dib.data[j * 4 + 0 + i * 4 * client.cx] = BYTE(float(dev_ptr->dib.data[j * 4 + 0 + i * 4 * client.cx]) * alpha);
dev_ptr->dib.data[j * 4 + 1 + i * 4 * client.cx] = BYTE(float(dev_ptr->dib.data[j * 4 + 1 + i * 4 * client.cx]) * alpha);
dev_ptr->dib.data[j * 4 + 2 + i * 4 * client.cx] = BYTE(float(dev_ptr->dib.data[j * 4 + 2 + i * 4 * client.cx]) * alpha);
dev_ptr->dib.data[j * 4 + 3 + i * 4 * client.cx] = mask_b;
}
}
HGDIOBJ prev_obj = SelectObject(dev_ptr->dib.hdc, dev_ptr->dib.image);
ClientToScreen(device->GetWindow(), &dest);
UpdateLayeredWindow(device->GetWindow(), hdc, &dest, &client,
dev_ptr->dib.hdc, &src, 0, &blend_func, ULW_ALPHA);
SelectObject(dev_ptr->dib.hdc, prev_obj);
ReleaseDC(device->GetWindow(), hdc);
}
}
scene->FreeObjects();
}
void evas_direct3d_line_draw(Direct3DDeviceHandler d3d, int x1, int y1, int x2, int y2)
{
DevicePtr *dev_ptr = SelectDevice(d3d);
D3DDevice *device = dev_ptr->device;
D3DScene *scene = dev_ptr->scene;
D3DContext *context = dev_ptr->context;
Ref<D3DObjectLine> line = scene->GetFreeObject<D3DObjectLine>();
if (line == NULL)
{
line = new D3DObjectLine();
scene->AddObject(line);
Log("New line object (total objects: %d)", scene->GetObjectCount());
}
else
{
line->SetFree(false);
Log("Line reused (object: %p)", line.Addr());
}
line->Setup(
2.f * float(x1) / float(device->GetWidth()) - 1.f,
2.f * (1.f - float(y1) / float(device->GetHeight())) - 1.f,
2.f * float(x2) / float(device->GetWidth()) - 1.f,
2.f * (1.f - float(y2) / float(device->GetHeight())) - 1.f,
context->color);
}
void evas_direct3d_rectangle_draw(Direct3DDeviceHandler d3d, int x, int y, int w, int h)
{
DevicePtr *dev_ptr = SelectDevice(d3d);
D3DDevice *device = dev_ptr->device;
D3DScene *scene = dev_ptr->scene;
D3DContext *context = dev_ptr->context;
Ref<D3DObjectRect> rect = scene->GetFreeObject<D3DObjectRect>();
if (rect == NULL)
{
rect = new D3DObjectRect();
scene->AddObject(rect);
Log("New rect object (total objects: %d)", scene->GetObjectCount());
}
else
{
rect->SetFree(false);
Log("Rect reused (object: %p)", rect.Addr());
}
rect->Setup(
2.f * float(x) / float(device->GetWidth()) - 1.f,
2.f * (1.f - float(y) / float(device->GetHeight())) - 1.f,
2.f * float(w) / float(device->GetWidth()),
-2.f * float(h) / float(device->GetHeight()),
context->color);
}
Direct3DImageHandler evas_direct3d_image_load(Direct3DDeviceHandler d3d,
const char *file, const char *key, int *error, Evas_Image_Load_Opts *lo)
{
DevicePtr *dev_ptr = SelectDevice(d3d);
D3DDevice *device = dev_ptr->device;
D3DScene *scene = dev_ptr->scene;
RGBA_Image *evas_image = evas_common_load_image_from_file(file, key, lo);
if (evas_image == NULL)
{
Log("Failed to load image from %s", file);
return NULL;
}
int image_width = evas_image->cache_entry.w;
int image_height = evas_image->cache_entry.h;
assert(image_width > 0 && image_height > 0);
D3DImageCache::CacheEntryInfo info;
ZeroMemory(&info, sizeof(info));
info.id = -1;
Ref<D3DObjectImage> image = new D3DObjectImage();
image->Init(info.u, info.v, info.du, info.dv, info.id,
info.width, info.height, evas_image->cache_entry.file);
image->SetFree(true);
scene->AddObject(image);
Log("New image object (total objects: %d)", scene->GetObjectCount());
ImagePtr *ptr = new ImagePtr;
ptr->ref = image;
ptr->img = evas_image;
return (Direct3DImageHandler)ptr;
}
Direct3DImageHandler evas_direct3d_image_new_from_data(Direct3DDeviceHandler d3d,
int w, int h, DWORD *image_data, int alpha, int cspace)
{
DevicePtr *dev_ptr = SelectDevice(d3d);
D3DDevice *device = dev_ptr->device;
D3DScene *scene = dev_ptr->scene;
int image_width = w;
int image_height = h;
assert(image_width > 0 && image_height > 0);
Ref<D3DObjectImage> image = new D3DObjectImage();
D3DImageCache::CacheEntryInfo info;
ZeroMemory(&info, sizeof(info));
if (!D3DImageCache::Current()->InsertImage(device, image_data,
image_width, image_height, info))
{
Log("Couldnt add image to the cache");
return NULL;
}
char buf[64];
sprintf(buf, "%p", image_data);
image->Init(info.u, info.v, info.du, info.dv, info.id,
info.width, info.height, buf);
image->SetFree(true);
scene->AddObject(image);
Log("New image object (total objects: %d)", scene->GetObjectCount());
ImagePtr *ptr = new ImagePtr;
ptr->ref = image;
ptr->img = NULL;
return (Direct3DImageHandler)ptr;
}
Direct3DImageHandler evas_direct3d_image_new_from_copied_data(Direct3DDeviceHandler d3d,
int w, int h, DWORD *image_data, int alpha, int cspace)
{
return evas_direct3d_image_new_from_data(d3d, w, h, image_data, alpha, cspace);
}
void evas_direct3d_image_free(Direct3DDeviceHandler d3d, Direct3DImageHandler image)
{
DevicePtr *dev_ptr = SelectDevice(d3d);
D3DDevice *device = dev_ptr->device;
D3DScene *scene = dev_ptr->scene;
ImagePtr *ptr = (ImagePtr *)image;
Ref<D3DObjectImage> image_ref = ptr->ref;
assert(!image_ref.IsNull());
scene->DeleteObject(image_ref);
delete ptr;
}
void evas_direct3d_image_data_put(Direct3DDeviceHandler d3d, Direct3DImageHandler image,
DWORD *image_data)
{
ImagePtr *ptr = (ImagePtr *)image;
Ref<D3DObjectImage> image_ref = ptr->ref;
//assert(!image_ref.IsNull());
if (image_ref.IsNull())
return;
if (!image_ref->UpdateImageData(image_data))
Log("Failed to update image data");
}
void evas_direct3d_image_data_get(Direct3DDeviceHandler d3d, Direct3DImageHandler image,
int to_write, DATA32 **image_data)
{
ImagePtr *ptr = (ImagePtr *)image;
Ref<D3DObjectImage> image_ref = ptr->ref;
if (image_ref.IsNull())
return;
if (image_data == NULL)
return;
assert(sizeof(DATA32) == sizeof(DWORD));
*image_data = (DATA32 *)image_ref->GetImageData();
}
void evas_direct3d_image_draw(Direct3DDeviceHandler d3d, Direct3DImageHandler image,
int src_x, int src_y, int src_w, int src_h,
int dst_x, int dst_y, int dst_w, int dst_h, int smooth)
{
ImagePtr *ptr = (ImagePtr *)image;
Ref<D3DObjectImage> image_ref = ptr->ref;
RGBA_Image *evas_image = ptr->img;
DevicePtr *dev_ptr = SelectDevice(d3d);
D3DDevice *device = dev_ptr->device;
D3DScene *scene = dev_ptr->scene;
//assert(!image_ref.IsNull());
if (image_ref.IsNull())
return;
if (!image_ref->IsValid())
{
TArray<D3DObjectImage *> images;
scene->GetObjectsOfType<D3DObjectImage>(images);
bool found = false;
for (int i = 0; i < images.Length(); i++)
{
if (images[i]->IsValid() &&
_stricmp(images[i]->GetSource(), image_ref->GetSource()) == 0)
{
images[i]->CopyTo(image_ref);
found = true;
Log("Image object info reused, source: \"%s\"", image_ref->GetSource());
break;
}
}
if (!found && evas_image != NULL)
evas_cache_image_load_data(&evas_image->cache_entry);
}
// If the image object wasnt initialized yet
if (evas_image != NULL && evas_image->image.data != NULL && !image_ref->IsValid())
{
D3DImageCache::CacheEntryInfo info;
ZeroMemory(&info, sizeof(info));
if (!D3DImageCache::Current()->InsertImage(device, (DWORD *)evas_image->image.data,
evas_image->cache_entry.w, evas_image->cache_entry.h, info))
{
Log("Couldnt add image to the cache");
return;
}
image_ref->Init(info.u, info.v, info.du, info.dv, info.id,
info.width, info.height, evas_image->cache_entry.file);
}
// Do not draw invalid objects
if (!image_ref->IsValid())
{
image_ref->SetFree(true);
return;
}
image_ref->Setup(
2.f * float(dst_x) / float(device->GetWidth()) - 1.f,
2.f * (1.f - float(dst_y) / float(device->GetHeight())) - 1.f,
2.f * float(dst_w) / float(device->GetWidth()),
-2.f * float(dst_h) / float(device->GetHeight()),
src_x, src_y, src_w, src_h);
image_ref->SetupColorFilter(dev_ptr->context->color_mul);
image_ref->SetFree(false);
}
void evas_direct3d_image_size_get(Direct3DImageHandler image, int *w, int *h)
{
ImagePtr *ptr = (ImagePtr *)image;
if (ptr == NULL)
return;
if (ptr->img != NULL)
{
if (w != NULL)
*w = ptr->img->cache_entry.w;
if (h != NULL)
*h = ptr->img->cache_entry.h;
}
else if (!ptr->ref.IsNull())
{
if (w != NULL)
*w = ptr->ref->GetWidth();
if (h != NULL)
*h = ptr->ref->GetHeight();
}
}
void evas_direct3d_image_border_set(Direct3DDeviceHandler d3d, Direct3DImageHandler image,
int l, int r, int t, int b)
{
ImagePtr *ptr = (ImagePtr *)image;
Ref<D3DObjectImage> image_ref = ptr->ref;
DevicePtr *dev_ptr = SelectDevice(d3d);
D3DDevice *device = dev_ptr->device;
if (image_ref.IsNull())
return;
int im_w, im_h;
if (ptr->img != NULL)
{
im_w = ptr->img->cache_entry.w;
im_h = ptr->img->cache_entry.h;
}
else
{
im_w = image_ref->GetWidth();
im_h = image_ref->GetHeight();
}
image_ref->SetupBorder(
D3DXVECTOR4(
2.f * float(l) / float(device->GetWidth()),
-2.f * float(t) / float(device->GetHeight()),
2.f * float(r) / float(device->GetWidth()),
-2.f * float(b) / float(device->GetHeight())),
D3DXVECTOR4(float(l) / float(im_w),
float(t) / float(im_h),
float(r) / float(im_w),
float(b) / float(im_h)));
}
void evas_direct3d_image_border_get(Direct3DDeviceHandler d3d, Direct3DImageHandler image,
int *l, int *r, int *t, int *b)
{
ImagePtr *ptr = (ImagePtr *)image;
Ref<D3DObjectImage> image_ref = ptr->ref;
DevicePtr *dev_ptr = SelectDevice(d3d);
D3DDevice *device = dev_ptr->device;
if (image_ref.IsNull())
return;
assert(l != NULL && r != NULL && b != NULL && t != NULL);
*l = (int)(0.5f * image_ref->GetBorderLeft() * device->GetWidth());
*r = (int)(0.5f * image_ref->GetBorderRight() * device->GetWidth());
*t = (int)(-0.5f * image_ref->GetBorderTop() * device->GetHeight());
*b = (int)(-0.5f * image_ref->GetBorderBottom() * device->GetHeight());
}
Direct3DFontGlyphHandler evas_direct3d_font_texture_new(Direct3DDeviceHandler d3d,
RGBA_Font_Glyph *fg)
{
DevicePtr *dev_ptr = SelectDevice(d3d);
D3DContext *context = dev_ptr->context;
D3DDevice *device = dev_ptr->device;
if (context->font.IsNull())
return NULL;
D3DObjectFont *font = (D3DObjectFont *)context->font.Addr();
// This is not reliable
//D3DObjectFont::Glyph *glyph = (D3DObjectFont::Glyph *)fg->ext_dat;
D3DObjectFont::Glyph *glyph = font->GetGlyph(fg);
if (glyph != NULL)
{
assert(glyph->Compare(fg));
return glyph;
}
glyph = font->AddGlyph(device, fg, fg->glyph_out->bitmap.buffer,
fg->glyph_out->bitmap.width, fg->glyph_out->bitmap.rows, fg->glyph_out->bitmap.pitch);
return (Direct3DFontGlyphHandler)glyph;
}
void evas_direct3d_font_texture_free(Direct3DFontGlyphHandler ft)
{
if (ft == NULL)
return;
D3DObjectFont::Glyph *glyph = (D3DObjectFont::Glyph *)ft;
RGBA_Font_Glyph *fg = (RGBA_Font_Glyph *)glyph->Source();
fg->ext_dat = NULL;
}
void evas_direct3d_font_texture_draw(Direct3DDeviceHandler d3d, void *, void *,
RGBA_Font_Glyph *fg, int x, int y)
{
DevicePtr *dev_ptr = SelectDevice(d3d);
D3DContext *context = dev_ptr->context;
D3DDevice *device = dev_ptr->device;
if (context->font.IsNull())
return;
D3DObjectFont *font = (D3DObjectFont *)context->font.Addr();
D3DObjectFont::Glyph *glyph = (D3DObjectFont::Glyph *)fg->ext_dat;
if (glyph == NULL)
return;
assert(glyph->Compare(fg));
font->SetColor(context->color);
font->PushForDraw(glyph, x, y);
font->SetFree(false);
}
void evas_direct3d_select_or_create_font(Direct3DDeviceHandler d3d, void *font)
{
// The Plan
// 1. Create D3DObjectFont with source string = "%p" (font)
// 2. Or find this object in the scene
// 3. On each texture_new call - fill internal texture with glyph, remember the
// glyph pointer - we'll use it.
DevicePtr *dev_ptr = SelectDevice(d3d);
D3DContext *context = dev_ptr->context;
if (!context->font.IsNull() && ((D3DObjectFont *)context->font.Addr())->Compare(font))
return;
D3DScene *scene = dev_ptr->scene;
static TArray<D3DObjectFont *> fonts;
scene->GetObjectsOfType<D3DObjectFont>(fonts);
for (int i = 0; i < fonts.Length(); i++)
{
if (fonts[i]->Compare(font))
{
context->font = fonts[i];
return;
}
}
D3DDevice *device = dev_ptr->device;
assert(dev_ptr->fonts_buffer_image_id >= 0);
Ref<D3DObjectFont> new_font = new D3DObjectFont(font, dev_ptr->fonts_buffer_image_id);
scene->AddObject(new_font);
context->font = new_font;
}
void evas_direct3d_font_free(Direct3DDeviceHandler d3d, void *font)
{
DevicePtr *dev_ptr = SelectDevice(d3d);
D3DContext *context = dev_ptr->context;
D3DScene *scene = dev_ptr->scene;
if (context->font.IsNull() || !((D3DObjectFont *)context->font.Addr())->Compare(font))
{
D3DScene *scene = dev_ptr->scene;
static TArray<D3DObjectFont *> fonts;
scene->GetObjectsOfType<D3DObjectFont>(fonts);
for (int i = 0; i < fonts.Length(); i++)
{
if (fonts[i]->Compare(font))
{
context->font = fonts[i];
break;
}
}
}
scene->DeleteObject(context->font);
context->font = NULL;
}
} // extern "C"

View File

@ -0,0 +1,12 @@
#include "evas_direct3d_object.h"
D3DObject::D3DObject()
{
_free = false;
}
D3DObject::~D3DObject()
{
}

View File

@ -0,0 +1,35 @@
#ifndef __EVAS_DIRECT3D_OBJECT_H__
#define __EVAS_DIRECT3D_OBJECT_H__
#include "evas_engine.h"
#include "ref.h"
class D3DDevice;
class D3DObject : virtual public Referenc
{
public:
D3DObject();
virtual ~D3DObject();
virtual void Draw(D3DDevice *d3d) = 0;
inline bool IsFree();
inline void SetFree(bool state);
private:
bool _free;
};
bool D3DObject::IsFree()
{
return _free;
}
void D3DObject::SetFree(bool state)
{
_free = state;
}
#endif // __EVAS_DIRECT3D_OBJECT_H__

View File

@ -0,0 +1,231 @@
//#define ENABLE_LOG_PRINTF
#include <string.h>
#include "evas_direct3d_object_font.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"
D3DObjectFont::Cache D3DObjectFont::_cache;
D3DObjectFont::D3DObjectFont(void *source, int image_id)
{
_image_id = image_id;
_color = 0xff000000;
_source = source;
D3DImageCache::Current()->AddImageUser(_image_id);
}
D3DObjectFont::~D3DObjectFont()
{
D3DImageCache::Current()->RemoveImageUser(_image_id);
}
void D3DObjectFont::CopyTo(D3DObjectFont *font)
{
assert(font != NULL);
font->_image_id = _image_id;
font->_source = _source;
D3DImageCache::Current()->AddImageUser(font->_image_id);
_glyphs.CopyTo(font->_glyphs);
}
void D3DObjectFont::BeginCache(int image_id)
{
if (_cache.enabled)
return;
int w = D3DImageCache::Current()->GetImageWidth(image_id);
int h = D3DImageCache::Current()->GetImageHeight(image_id);
_cache.enabled = true;
_cache.image_id = image_id;
_cache.data.Allocate(w * h);
if (_cache.dirty.Length() != h)
{
_cache.dirty.Allocate(h);
memset(_cache.dirty.Data(), 0xff, sizeof(POINT) * _cache.dirty.Length());
}
ZeroMemory(_cache.data.Data(), sizeof(DWORD) * _cache.data.Length());
_cache.width = w;
_cache.height = h;
_cache.valid_rect.left = w;
_cache.valid_rect.right = 0;
_cache.valid_rect.top = h;
_cache.valid_rect.bottom = 0;
}
void D3DObjectFont::Draw(D3DDevice *d3d)
{
assert(_cache.image_id == _image_id);
}
void D3DObjectFont::EndCache(D3DDevice *d3d)
{
if (!_cache.enabled)
return;
_cache.enabled = false;
if (_cache.data.Length() == 0)
return;
D3DImageCache::CacheEntryInfo info;
ZeroMemory(&info, sizeof(info));
info.id = _cache.image_id;
info.width = _cache.width;
info.height = _cache.height;
if (!D3DImageCache::Current()->UpdateImageDataWithDirtyInfo(info,
_cache.data.Data(), _cache.dirty.Data()))
//if (!D3DImageCache::Current()->UpdateImageDataDiscard(info, _cache.data.Data()));
{
return;
}
D3DShaderPack::Current()->SetVDecl(d3d, D3DShaderPack::VDECL_XYUV);
D3DShaderPack::Current()->SetVS(d3d, D3DShaderPack::VS_COPY_UV);
D3DShaderPack::Current()->SetPS(d3d, D3DShaderPack::PS_TEX_2); // This image is in s1
D3DImageCache::Current()->SelectImageToDevice(d3d, _cache.image_id);
const FLOAT half_x = 0.5f / FLOAT(_cache.width);
const FLOAT half_y = 0.5f / FLOAT(_cache.height);
FLOAT left = FLOAT(_cache.valid_rect.left - 5) / FLOAT(_cache.width),
top = FLOAT(_cache.valid_rect.top - 5) / FLOAT(_cache.height),
right = FLOAT(_cache.valid_rect.right + 5) / FLOAT(_cache.width),
bottom = FLOAT(_cache.valid_rect.bottom + 5) / FLOAT(_cache.height);
const Vertex data[6] = {
{left * 2 - 1, 2 * (1 - bottom) - 1, left + half_x, bottom + half_y},
{left * 2 - 1, 2 * (1 - top) - 1, left + half_x, top + half_y},
{right * 2 - 1, 2 * (1 - bottom) - 1, right + half_x, bottom + half_y},
{right * 2 - 1, 2 * (1 - bottom) - 1, right + half_x, bottom + half_y},
{left * 2 - 1, 2 * (1 - top) - 1, left + half_x, top + half_y},
{right * 2 - 1, 2 * (1 - top) - 1, right + half_x, top + half_y}};
d3d->GetDevice()->DrawPrimitiveUP(D3DPT_TRIANGLELIST, 2, data, sizeof(Vertex));
//D3DImageCache::Current()->UpdateImageDataWithDirtyInfo(info, NULL, _cache.dirty.Data());
}
D3DObjectFont::Glyph *D3DObjectFont::GetGlyph(void *source)
{
if (_image_id < 0)
{
Log("Font is not initialized");
return NULL;
}
for (int i = 0; i < _glyphs.Length(); i++)
{
if (_glyphs[i]->Compare(source))
return _glyphs[i];
}
return NULL;
}
D3DObjectFont::Glyph *D3DObjectFont::AddGlyph(D3DDevice *d3d, void *source,
BYTE *data8, int width, int height, int pitch)
{
if (_image_id < 0)
{
Log("Font is not initialized");
return NULL;
}
for (int i = 0; i < _glyphs.Length(); i++)
{
if (_glyphs[i]->Compare(source))
return _glyphs[i];
}
Ref<Glyph> glyph = new Glyph(source);
glyph->_data.Allocate(width * height);
glyph->_width = width;
glyph->_height = height;
for (int i = 0; i < height; i++)
CopyMemory(&glyph->_data[i * width], &data8[i * pitch], width);
Log("Glyph added (%p) (%dx%d)", source, width, height);
_glyphs.Add(glyph);
return _glyphs.Last()->Addr();
}
void D3DObjectFont::PushForDraw(Glyph *glyph, int x, int y)
{
BeginCache(_image_id);
// Uff, I'm not sure about multiple windows...
#define LERP(a, b, t1, t2) (BYTE)(FLOAT(a) * (t1) + FLOAT(b) * (t2))
Color dc, sc;
FLOAT a;
sc.color = _color;
const FLOAT color_alpha = sc.Alpha();
DWORD *data = _cache.data.Data();
BYTE *gdata = glyph->_data.Data();
const int glyph_height = glyph->_height;
const int cache_height = _cache.height;
const int glyph_width = glyph->_width;
const int cache_width = _cache.width;
for (int i = 0, yi = y; i < glyph_height && yi < cache_height; i++, yi++)
{
if (yi < 0)
continue;
DWORD *dst = data + ((yi) * cache_width + x);
BYTE *src = gdata + (i * glyph_width);
POINT *dirty_yi = &_cache.dirty[yi];
if (_cache.valid_rect.top > yi)
_cache.valid_rect.top = yi;
if (_cache.valid_rect.bottom < yi)
_cache.valid_rect.bottom = yi;
for (int j = 0, xj = x; j < glyph_width && xj < cache_width; j++, xj++, dst++, src++)
{
if (xj < 0)
continue;
BYTE glyph_pix = *src;
if (glyph_pix == 0)
continue;
if (dirty_yi->x >= 0 && dirty_yi->y < 0)
dirty_yi->x = 0, dirty_yi->y = cache_width - 1;
else
{
if (dirty_yi->x < 0 || dirty_yi->x > xj)
dirty_yi->x = xj;
if (dirty_yi->y < 0 || dirty_yi->y < xj)
dirty_yi->y = xj;
}
if (_cache.valid_rect.left > xj)
_cache.valid_rect.left = xj;
if (_cache.valid_rect.right < xj)
_cache.valid_rect.right = xj;
if (glyph_pix == 0xff && sc.a == 0xff)
{
*dst = sc.color;
continue;
}
a = FLOAT(glyph_pix) * color_alpha / 255.f;
if (*dst == 0)
{
*dst = (BYTE(255.f * a) << 24) | (0x00ffffff & sc.color);
continue;
}
dc.color = *dst;
dc.r = LERP(dc.r, sc.r, 1 - a, a);
dc.g = LERP(dc.g, sc.g, 1 - a, a);
dc.b = LERP(dc.b, sc.b, 1 - a, a);
dc.a = max(dc.a, BYTE(255.f * a));
*dst = dc.color;
}
}
}

View File

@ -0,0 +1,113 @@
#ifndef __EVAS_DIRECT3D_OBJECT_FONT_H__
#define __EVAS_DIRECT3D_OBJECT_FONT_H__
#include "evas_engine.h"
#include "ref.h"
#include "array.h"
#include "evas_direct3d_object.h"
class D3DObjectFont : public D3DObject
{
public:
class Glyph : public Referenc
{
public:
Glyph(void *source)
: _source(source), _width(0), _height(0) {};
bool Compare(void *source)
{
return (_source == source);
}
void *Source()
{
return _source;
}
private:
friend class D3DObjectFont;
void *_source;
TArray<BYTE> _data;
int _width;
int _height;
};
public:
D3DObjectFont(void *source, int image_id);
~D3DObjectFont();
inline bool Compare(void *source);
void CopyTo(D3DObjectFont *font);
virtual void Draw(D3DDevice *d3d);
static void EndCache(D3DDevice *d3d);
inline void SetColor(DWORD color);
Glyph *GetGlyph(void *source);
Glyph *AddGlyph(D3DDevice *d3d, void *source, BYTE *data8, int width, int height, int pitch);
void PushForDraw(Glyph *glyph, int x, int y);
protected:
static void BeginCache(int image_id);
private:
struct Vertex
{
FLOAT x, y;
FLOAT u, v;
};
struct Color
{
union
{
struct
{
BYTE b, g, r, a;
};
DWORD color;
};
FLOAT Alpha() { return FLOAT(a) / 255.f; }
};
class Cache
{
public:
Cache()
: enabled(false), image_id(-1), width(0), height(0) {};
public:
TArray<DWORD> data;
TArray<POINT> dirty; // Start, End
bool enabled;
int image_id;
int width;
int height;
RECT valid_rect;
};
private:
DWORD _color;
void *_source;
int _image_id;
TArray<Ref<Glyph> > _glyphs;
static Cache _cache;
};
bool D3DObjectFont::Compare(void *source)
{
return (_source == source);
}
void D3DObjectFont::SetColor(DWORD color)
{
_color = color;
}
#endif // __EVAS_DIRECT3D_OBJECT_FONT_H__

View File

@ -0,0 +1,318 @@
//#define ENABLE_LOG_PRINTF
#include <string.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;
}
Log("Image cache drawn: %d items, %d groups", _cache.Length(), groups.Length());
_cache_enabled = false;
}
void D3DObjectImage::Draw(D3DDevice *d3d)
{
_dirty = false;
Log("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();
}

View File

@ -0,0 +1,127 @@
#ifndef __EVAS_DIRECT3D_OBJECT_IMAGE_H__
#define __EVAS_DIRECT3D_OBJECT_IMAGE_H__
#include "evas_engine.h"
#include "ref.h"
#include "array.h"
#include "evas_direct3d_object.h"
class D3DObjectImage : public D3DObject
{
public:
D3DObjectImage();
virtual ~D3DObjectImage();
void CopyTo(D3DObjectImage *image);
static void BeginCache();
virtual void Draw(D3DDevice *d3d);
static void EndCache(D3DDevice *d3d);
void Init(FLOAT u, FLOAT v, FLOAT du, FLOAT dv, int image_id,
int width, int height, const char *source);
void Setup(FLOAT x, FLOAT y, FLOAT w, FLOAT h,
int sx, int sy, int sw, int sh);
void SetupColorFilter(DWORD color);
void SetupBorder(const D3DXVECTOR4 &world_border, const D3DXVECTOR4 &pix_border);
inline bool IsValid();
inline const char *GetSource();
inline int GetWidth();
inline int GetHeight();
inline FLOAT GetBorderLeft();
inline FLOAT GetBorderRight();
inline FLOAT GetBorderTop();
inline FLOAT GetBorderBottom();
bool UpdateImageData(DWORD *image_data);
DWORD *GetImageData();
private:
struct Vertex
{
FLOAT x, y;
FLOAT u, v;
D3DCOLOR col;
};
struct GroupDesc
{
int num;
int id;
};
private:
Vertex *MakeData();
Vertex *MakeDataBorder();
private:
FLOAT _x, _y, _w, _h;
FLOAT _sx, _sy, _sw, _sh;
D3DXVECTOR4 _border;
D3DXVECTOR4 _uvborder;
FLOAT _u, _v, _du, _dv;
int _image_id;
int _width, _height;
D3DCOLOR _color;
int _cache_i;
bool _with_border;
bool _dirty;
TArray<DWORD> _image_data;
bool _image_data_updated;
char _source[256];
Vertex _data[54];
static TArray<D3DObjectImage *> _cache;
static bool _cache_enabled;
};
bool D3DObjectImage::IsValid()
{
return _image_id >= 0 && _width > 0 && _height > 0;
}
const char *D3DObjectImage::GetSource()
{
return _source;
}
int D3DObjectImage::GetWidth()
{
return _width;
}
int D3DObjectImage::GetHeight()
{
return _height;
}
FLOAT D3DObjectImage::GetBorderLeft()
{
return _border.x;
}
FLOAT D3DObjectImage::GetBorderRight()
{
return _border.z;
}
FLOAT D3DObjectImage::GetBorderTop()
{
return _border.y;
}
FLOAT D3DObjectImage::GetBorderBottom()
{
return _border.w;
}
#endif // __EVAS_DIRECT3D_OBJECT_IMAGE_H__

View File

@ -0,0 +1,60 @@
#include "evas_direct3d_object_line.h"
#include "evas_direct3d_device.h"
#include "evas_direct3d_shader_pack.h"
TArray<D3DObjectLine::Vertex> D3DObjectLine::_cache;
bool D3DObjectLine::_cache_enabled = false;
D3DObjectLine::D3DObjectLine()
{
_x1 = _y1 = 0;
_x2 = _y2 = 0;
}
void D3DObjectLine::BeginCache()
{
_cache.Allocate(0);
_cache_enabled = true;
}
void D3DObjectLine::EndCache(D3DDevice *d3d)
{
if (!_cache_enabled || _cache.Length() == 0)
return;
D3DShaderPack::Current()->SetVDecl(d3d, D3DShaderPack::VDECL_XYC);
D3DShaderPack::Current()->SetVS(d3d, D3DShaderPack::VS_COPY_COLOR);
D3DShaderPack::Current()->SetPS(d3d, D3DShaderPack::PS_COLOR);
d3d->GetDevice()->DrawPrimitiveUP(D3DPT_LINELIST, _cache.Length() / 2,
_cache.Data(), sizeof(Vertex));
Log("Line cache drawn: %d items", _cache.Length() / 2);
_cache_enabled = false;
}
void D3DObjectLine::Draw(D3DDevice *d3d)
{
Vertex data[2] = {{_x1, _y1, _color}, {_x2, _y2, _color}};
if (!_cache_enabled)
{
D3DShaderPack::Current()->SetVDecl(d3d, D3DShaderPack::VDECL_XYC);
D3DShaderPack::Current()->SetVS(d3d, D3DShaderPack::VS_COPY_COLOR);
D3DShaderPack::Current()->SetPS(d3d, D3DShaderPack::PS_COLOR);
d3d->GetDevice()->DrawPrimitiveUP(D3DPT_LINELIST, 1, data, sizeof(Vertex));
}
else
{
_cache.Add(data[0]);
_cache.Add(data[1]);
}
}
void D3DObjectLine::Setup(FLOAT x1, FLOAT y1, FLOAT x2, FLOAT y2, DWORD color)
{
_x1 = x1;
_y1 = y1;
_x2 = x2;
_y2 = y2;
_color = color;
}

View File

@ -0,0 +1,37 @@
#ifndef __EVAS_DIRECT3D_OBJECT_LINE_H__
#define __EVAS_DIRECT3D_OBJECT_LINE_H__
#include "evas_engine.h"
#include "ref.h"
#include "array.h"
#include "evas_direct3d_object.h"
class D3DObjectLine : public D3DObject
{
public:
D3DObjectLine();
static void BeginCache();
virtual void Draw(D3DDevice *d3d);
static void EndCache(D3DDevice *d3d);
void Setup(FLOAT x1, FLOAT y1, FLOAT x2, FLOAT y2, DWORD color);
private:
FLOAT _x1, _y1, _x2, _y2;
DWORD _color;
private:
struct Vertex
{
FLOAT x, y;
DWORD color;
};
static TArray<Vertex> _cache;
static bool _cache_enabled;
};
#endif // __EVAS_DIRECT3D_OBJECT_LINE_H__

View File

@ -0,0 +1,65 @@
#include "evas_direct3d_object_rect.h"
#include "evas_direct3d_device.h"
#include "evas_direct3d_shader_pack.h"
TArray<D3DObjectRect::Vertex> D3DObjectRect::_cache;
bool D3DObjectRect::_cache_enabled = false;
D3DObjectRect::D3DObjectRect()
{
_x = _y = 0;
_w = _h = 0;
}
void D3DObjectRect::BeginCache()
{
_cache.Allocate(0);
_cache_enabled = true;
}
void D3DObjectRect::EndCache(D3DDevice *d3d)
{
if (!_cache_enabled || _cache.Length() == 0)
return;
D3DShaderPack::Current()->SetVDecl(d3d, D3DShaderPack::VDECL_XYC);
D3DShaderPack::Current()->SetVS(d3d, D3DShaderPack::VS_COPY_COLOR);
D3DShaderPack::Current()->SetPS(d3d, D3DShaderPack::PS_COLOR);
d3d->GetDevice()->DrawPrimitiveUP(D3DPT_TRIANGLELIST, _cache.Length() / 3,
_cache.Data(), sizeof(Vertex));
Log("Rect cache drawn: %d items", _cache.Length() / 6);
_cache_enabled = false;
}
void D3DObjectRect::Draw(D3DDevice *d3d)
{
Vertex data[6] = {
{_x, _y, _color}, {_x + _w, _y, _color}, {_x, _y + _h, _color},
{_x, _y + _h, _color}, {_x + _w, _y, _color}, {_x + _w, _y + _h, _color}};
if (!_cache_enabled)
{
D3DShaderPack::Current()->SetVDecl(d3d, D3DShaderPack::VDECL_XYC);
D3DShaderPack::Current()->SetVS(d3d, D3DShaderPack::VS_COPY_COLOR);
D3DShaderPack::Current()->SetPS(d3d, D3DShaderPack::PS_COLOR);
d3d->GetDevice()->DrawPrimitiveUP(D3DPT_TRIANGLELIST, 2, data, sizeof(Vertex));
}
else
{
_cache.Add(data[0]);
_cache.Add(data[1]);
_cache.Add(data[2]);
_cache.Add(data[3]);
_cache.Add(data[4]);
_cache.Add(data[5]);
}
}
void D3DObjectRect::Setup(FLOAT x, FLOAT y, FLOAT w, FLOAT h, DWORD color)
{
_x = x;
_y = y;
_w = w;
_h = h;
_color = color;
}

View File

@ -0,0 +1,37 @@
#ifndef __EVAS_DIRECT3D_OBJECT_RECT_H__
#define __EVAS_DIRECT3D_OBJECT_RECT_H__
#include "evas_engine.h"
#include "ref.h"
#include "array.h"
#include "evas_direct3d_object.h"
class D3DObjectRect : public D3DObject
{
public:
D3DObjectRect();
static void BeginCache();
virtual void Draw(D3DDevice *d3d);
static void EndCache(D3DDevice *d3d);
void Setup(FLOAT x, FLOAT y, FLOAT w, FLOAT h, DWORD color);
private:
FLOAT _x, _y, _w, _h;
DWORD _color;
private:
struct Vertex
{
FLOAT x, y;
DWORD color;
};
static TArray<Vertex> _cache;
static bool _cache_enabled;
};
#endif // __EVAS_DIRECT3D_OBJECT_RECT_H__

View File

@ -0,0 +1,33 @@
#include "evas_direct3d_scene.h"
D3DScene::D3DScene()
{
}
void D3DScene::FreeObjects()
{
for (int i = 0; i < _objects.Length(); i++)
_objects[i]->SetFree(true);
}
void D3DScene::DrawAll(D3DDevice *d3d)
{
for (int i = 0; i < _objects.Length(); i++)
{
if (!_objects[i]->IsFree())
_objects[i]->Draw(d3d);
}
}
void D3DScene::DeleteObject(D3DObject *object)
{
for (int i = 0; i < _objects.Length(); i++)
{
if (_objects[i].Addr() == object)
{
_objects.Replace(i);
return;
}
}
}

View File

@ -0,0 +1,63 @@
#ifndef __EVAS_DIRECT3D_SCENE_H__
#define __EVAS_DIRECT3D_SCENE_H__
#include "evas_engine.h"
#include <assert.h>
#include <typeinfo>
#include "ref.h"
#include "array.h"
#include "evas_direct3d_object.h"
class D3DDevice;
class D3DScene : virtual public Referenc
{
public:
D3DScene();
void FreeObjects();
inline void AddObject(D3DObject *object);
inline int GetObjectCount();
void DeleteObject(D3DObject *object);
void DrawAll(D3DDevice *d3d);
template <class T> T *GetFreeObject()
{
for (int i = 0; i < _objects.Length(); i++)
{
if (typeid(T) == typeid(*_objects[i].Addr()) && _objects[i]->IsFree())
return (T *)_objects[i].Addr();
}
return NULL;
}
template <class T> void GetObjectsOfType(TArray<T *> &res)
{
for (int i = 0; i < _objects.Length(); i++)
{
if (typeid(T) == typeid(*_objects[i].Addr()))
res.Add((T *)_objects[i].Addr());
}
}
private:
TArray<Ref<D3DObject> > _objects;
};
void D3DScene::AddObject(D3DObject *object)
{
assert(object != NULL);
_objects.Add(object);
}
int D3DScene::GetObjectCount()
{
return _objects.Length();
}
#endif // __EVAS_DIRECT3D_SCENE_H__

View File

@ -0,0 +1,340 @@
#include "evas_direct3d_shader_pack.h"
#include "evas_direct3d_device.h"
#include <assert.h>
Ref<D3DShaderPack> D3DShaderPack::_this;
D3DShaderPack::D3DShaderPack()
{
}
D3DShaderPack::~D3DShaderPack()
{
Uninitialize();
}
D3DShaderPack *D3DShaderPack::Current()
{
if (_this.IsNull())
_this = new D3DShaderPack();
return _this;
}
void D3DShaderPack::SetCurrent(D3DShaderPack *obj)
{
_this = obj;
}
bool D3DShaderPack::Initialize(D3DDevice *d3d)
{
bool res = true;
if (!(res = InitVertexDeclarations(d3d) && res))
Log("Failed to create vdecl set");
if (!(res = InitVertexShaders(d3d) && res))
Log("Failed to create vs set");
if (!(res = InitPixelShaders(d3d) && res))
Log("Failed to create ps set");
return res;
}
void D3DShaderPack::Uninitialize()
{
for (int i = 0; i < _vdecl.Length(); i++)
{
if (_vdecl[i] != NULL)
{
_vdecl[i]->Release();
_vdecl[i] = NULL;
}
}
for (int i = 0; i < _vs.Length(); i++)
{
if (_vs[i] != NULL)
{
_vs[i]->Release();
_vs[i] = NULL;
}
}
for (int i = 0; i < _ps.Length(); i++)
{
if (_ps[i] != NULL)
{
_ps[i]->Release();
_ps[i] = NULL;
}
}
}
bool D3DShaderPack::InitVertexDeclarations(D3DDevice *d3d)
{
_vdecl.Allocate(VDECL_NUM);
_vdecl.Set(NULL);
LPDIRECT3DVERTEXDECLARATION9 vdecl = NULL;
{
D3DVERTEXELEMENT9 elements[] = {
{0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
{0, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
D3DDECL_END()
};
if (FAILED(d3d->GetDevice()->CreateVertexDeclaration(elements, &vdecl)))
return false;
if (vdecl == NULL)
return false;
}
_vdecl[VDECL_XYC] = vdecl;
vdecl = NULL;
{
D3DVERTEXELEMENT9 elements[] = {
{0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
{0, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
D3DDECL_END()
};
if (FAILED(d3d->GetDevice()->CreateVertexDeclaration(elements, &vdecl)))
return false;
if (vdecl == NULL)
return false;
}
_vdecl[VDECL_XYUV] = vdecl;
vdecl = NULL;
{
D3DVERTEXELEMENT9 elements[] = {
{0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
{0, 8, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
{0, 16, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
D3DDECL_END()
};
if (FAILED(d3d->GetDevice()->CreateVertexDeclaration(elements, &vdecl)))
return false;
if (vdecl == NULL)
return false;
}
_vdecl[VDECL_XYUVC] = vdecl;
vdecl = NULL;
{
D3DVERTEXELEMENT9 elements[] = {
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
{0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
{0, 20, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
D3DDECL_END()
};
if (FAILED(d3d->GetDevice()->CreateVertexDeclaration(elements, &vdecl)))
return false;
if (vdecl == NULL)
return false;
}
_vdecl[VDECL_XYZUVC] = vdecl;
return true;
}
bool D3DShaderPack::InitVertexShaders(D3DDevice *d3d)
{
_vs.Allocate(VS_NUM);
_vs.Set(NULL);
{
char buf[] =
"struct VsInput { float2 pos : POSITION; float4 col : COLOR; };\n"
"struct VsOutput { float4 pos : POSITION; float4 col : COLOR0; };\n"
"VsOutput main(VsInput vs_in) {\n"
"VsOutput vs_out;\n"
"vs_out.pos = float4(vs_in.pos, 0, 1);\n"
"vs_out.col = vs_in.col;\n"
"return vs_out;}";
_vs[VS_COPY_COLOR] = (LPDIRECT3DVERTEXSHADER9)
CompileShader(d3d, true, "CopyColor", buf, sizeof(buf) - 1);
if (_vs[VS_COPY_COLOR] == NULL)
return false;
}
{
char buf[] =
"struct VsInput { float2 pos : POSITION; float2 tex : TEXCOORD0; };\n"
"struct VsOutput { float4 pos : POSITION; float2 tex : TEXCOORD0; };\n"
"VsOutput main(VsInput vs_in) {\n"
"VsOutput vs_out;\n"
"vs_out.pos = float4(vs_in.pos, 0, 1);\n"
"vs_out.tex = vs_in.tex;\n"
"return vs_out;}";
_vs[VS_COPY_UV] = (LPDIRECT3DVERTEXSHADER9)
CompileShader(d3d, true, "CopyUV", buf, sizeof(buf) - 1);
if (_vs[VS_COPY_UV] == NULL)
return false;
}
{
char buf[] =
"struct VsInput { float2 pos : POSITION; float2 tex : TEXCOORD0; float4 col : COLOR; };\n"
"struct VsOutput { float4 pos : POSITION; float2 tex : TEXCOORD0; float4 col : COLOR0; };\n"
"VsOutput main(VsInput vs_in) {\n"
"VsOutput vs_out;\n"
"vs_out.pos = float4(vs_in.pos, 0, 1);\n"
"vs_out.tex = vs_in.tex;\n"
"vs_out.col = vs_in.col;\n"
"return vs_out;}";
_vs[VS_COPY_UV_COLOR] = (LPDIRECT3DVERTEXSHADER9)
CompileShader(d3d, true, "CopyUVColor", buf, sizeof(buf) - 1);
if (_vs[VS_COPY_UV_COLOR] == NULL)
return false;
}
{
char buf[] =
"struct VsInput { float3 pos : POSITION; float2 tex : TEXCOORD0; float4 col : COLOR; };\n"
"struct VsOutput { float4 pos : POSITION; float2 tex : TEXCOORD0; float4 col : COLOR0; };\n"
"VsOutput main(VsInput vs_in) {\n"
"VsOutput vs_out;\n"
"vs_out.pos = float4(vs_in.pos, 1);\n"
"vs_out.tex = vs_in.tex;\n"
"vs_out.col = vs_in.col;\n"
"return vs_out;}";
_vs[VS_COPY_UV_COLOR_Z] = (LPDIRECT3DVERTEXSHADER9)
CompileShader(d3d, true, "CopyUVColorZ", buf, sizeof(buf) - 1);
if (_vs[VS_COPY_UV_COLOR_Z] == NULL)
return false;
}
return true;
}
bool D3DShaderPack::InitPixelShaders(D3DDevice *d3d)
{
_ps.Allocate(PS_NUM);
_ps.Set(NULL);
{
char buf[] =
"struct VsOutput { float4 pos : POSITION; float4 col : COLOR0; };\n"
"float4 main(VsOutput ps_in) : COLOR0 {\n"
"return ps_in.col;}";
_ps[PS_COLOR] = (LPDIRECT3DPIXELSHADER9)
CompileShader(d3d, false, "Color", buf, sizeof(buf) - 1);
if (_ps[PS_COLOR] == NULL)
return false;
}
{
char buf[] =
"sampler Texture : register(s0);\n"
"struct VsOutput { float4 pos : POSITION; float2 tex : TEXCOORD0; };\n"
"float4 main(VsOutput ps_in) : COLOR0 {\n"
"return tex2D(Texture, ps_in.tex);}";
_ps[PS_TEX] = (LPDIRECT3DPIXELSHADER9)
CompileShader(d3d, false, "Tex", buf, sizeof(buf) - 1);
if (_ps[PS_TEX] == NULL)
return false;
}
{
char buf[] =
"sampler Texture : register(s0);\n"
"struct VsOutput { float4 pos : POSITION; float2 tex : TEXCOORD0; float4 col : COLOR0; };\n"
"float4 main(VsOutput ps_in) : COLOR0 {\n"
"return tex2D(Texture, ps_in.tex) * ps_in.col;}";
_ps[PS_TEX_COLOR_FILTER] = (LPDIRECT3DPIXELSHADER9)
CompileShader(d3d, false, "TexColorFilter", buf, sizeof(buf) - 1);
if (_ps[PS_TEX_COLOR_FILTER] == NULL)
return false;
}
{
char buf[] =
"sampler Texture : register(s1);\n"
"struct VsOutput { float4 pos : POSITION; float2 tex : TEXCOORD0; };\n"
"float4 main(VsOutput ps_in) : COLOR0 {\n"
"return tex2D(Texture, ps_in.tex);}";
_ps[PS_TEX_2] = (LPDIRECT3DPIXELSHADER9)
CompileShader(d3d, false, "Tex2", buf, sizeof(buf) - 1);
if (_ps[PS_TEX_2] == NULL)
return false;
}
return true;
}
void *D3DShaderPack::CompileShader(D3DDevice *d3d, bool make_vs,
const char *name, const char *buf, int size)
{
LPD3DXBUFFER compiled_res = NULL;
LPD3DXBUFFER error_msgs = NULL;
HRESULT res = D3DXCompileShader(buf, size, NULL, NULL,
"main", make_vs ? "vs_2_0" : "ps_2_0", // ?
0, &compiled_res, &error_msgs, NULL);
if (FAILED(res))
{
Log("Shader %s compilation failed, code = %X", name, res);
if (error_msgs == NULL)
return NULL;
const char *mess = (const char *)error_msgs->GetBufferPointer();
Log("Error output:\n%s", mess);
error_msgs->Release();
return NULL;
}
if (error_msgs != NULL)
error_msgs->Release();
void *res_ptr = NULL;
if (make_vs)
{
LPDIRECT3DVERTEXSHADER9 vs;
res = d3d->GetDevice()->CreateVertexShader((DWORD *)compiled_res->GetBufferPointer(), &vs);
res_ptr = (void *)vs;
}
else
{
LPDIRECT3DPIXELSHADER9 ps;
res = d3d->GetDevice()->CreatePixelShader((DWORD *)compiled_res->GetBufferPointer(), &ps);
res_ptr = (void *)ps;
}
compiled_res->Release();
if (FAILED(res))
{
Log("Shader %s creation failed, code = %X", name, res);
return NULL;
}
return res_ptr;
}
bool D3DShaderPack::SetVDecl(D3DDevice *d3d, int id)
{
if (id < 0 || id >= _vdecl.Length() || _vdecl[id] == NULL)
return false;
assert(d3d != NULL);
d3d->GetDevice()->SetVertexDeclaration(_vdecl[id]);
return true;
}
bool D3DShaderPack::SetVS(D3DDevice *d3d, int id)
{
if (id < 0 || id >= _vs.Length() || _vs[id] == NULL)
return false;
assert(d3d != NULL);
d3d->GetDevice()->SetVertexShader(_vs[id]);
return true;
}
bool D3DShaderPack::SetPS(D3DDevice *d3d, int id)
{
if (id < 0 || id >= _ps.Length() || _ps[id] == NULL)
return false;
assert(d3d != NULL);
d3d->GetDevice()->SetPixelShader(_ps[id]);
return true;
}

View File

@ -0,0 +1,75 @@
#ifndef __EVAS_DIRECT3D_SHADER_PACK_H__
#define __EVAS_DIRECT3D_SHADER_PACK_H__
#include "evas_engine.h"
#include "ref.h"
#include "array.h"
class D3DDevice;
class D3DShaderPack : virtual public Referenc
{
public:
~D3DShaderPack();
static D3DShaderPack *Current();
static void SetCurrent(D3DShaderPack *obj);
bool Initialize(D3DDevice *d3d);
void Uninitialize();
bool SetVDecl(D3DDevice *d3d, int id);
bool SetVS(D3DDevice *d3d, int id);
bool SetPS(D3DDevice *d3d, int id);
public:
enum VDECL
{
VDECL_XYC = 0,
VDECL_XYUV,
VDECL_XYUVC,
VDECL_XYZUVC,
VDECL_NUM
};
enum VS
{
VS_COPY_COLOR = 0,
VS_COPY_UV,
VS_COPY_UV_COLOR,
VS_COPY_UV_COLOR_Z,
VS_NUM
};
enum PS
{
PS_COLOR = 0,
PS_TEX,
PS_TEX_COLOR_FILTER,
PS_TEX_2,
PS_NUM
};
private:
D3DShaderPack();
bool InitVertexDeclarations(D3DDevice *d3d);
bool InitVertexShaders(D3DDevice *d3d);
bool InitPixelShaders(D3DDevice *d3d);
void *CompileShader(D3DDevice *d3d, bool make_vs, const char *name,
const char *buf, int size);
private:
TArray<LPDIRECT3DVERTEXDECLARATION9> _vdecl;
TArray<LPDIRECT3DVERTEXSHADER9> _vs;
TArray<LPDIRECT3DPIXELSHADER9> _ps;
static Ref<D3DShaderPack> _this;
};
#endif // __EVAS_DIRECT3D_SHADER_PACK_H__

View File

@ -0,0 +1,154 @@
//#define ENABLE_LOG_PRINTF
#include "evas_direct3d_vertex_buffer_cache.h"
#include "evas_direct3d_device.h"
#include <assert.h>
Ref<D3DVertexBufferCache> D3DVertexBufferCache::_this;
D3DVertexBufferCache::D3DVertexBufferCache()
{
size_border_low = 0.6; // We can reuse buffer on 60%
size_border_high = 0.2; // We can reallocate the buffer on 20%
}
D3DVertexBufferCache::~D3DVertexBufferCache()
{
Uninitialize();
}
D3DVertexBufferCache *D3DVertexBufferCache::Current()
{
if (_this.IsNull())
_this = new D3DVertexBufferCache();
return _this;
}
void D3DVertexBufferCache::SetCurrent(D3DVertexBufferCache *obj)
{
_this = obj;
}
void D3DVertexBufferCache::Uninitialize()
{
for (int i = 0; i < _cache.Length(); i++)
{
assert(_cache[i].vb != NULL);
_cache[i].vb->Release();
}
_cache.Resize();
}
bool D3DVertexBufferCache::InitBuffer(D3DDevice *d3d, BYTE *data, int size, CacheEntryInfo &info)
{
assert(d3d != NULL);
assert(data != NULL);
assert(size > 0);
int best = FindBestEntry(size);
CacheEntry *ce = NULL;
// Reallocate
if (best >= 0 && _cache[best].size < size)
{
DeleteEntry(best);
best = -1;
}
// New
if (best < 0)
{
CacheEntry new_entry;
if (!CreateEntry(d3d, new_entry, size))
{
Log("Failed to create new vbcache entry");
return false;
}
_cache.Add(new_entry);
info.id = _cache.Length() - 1;
ce = _cache.Last();
}
else
{
info.id = best;
ce = &_cache[best];
}
assert(ce != NULL);
if (!InsertData(*ce, data, size))
{
Log("Failed to insert vbcache data");
return false;
}
return true;
}
bool D3DVertexBufferCache::SelectBufferToDevice(D3DDevice *device, int id, int vertex_size)
{
if (id < 0 || id >= _cache.Length())
return false;
return SUCCEEDED(device->GetDevice()->SetStreamSource(0, _cache[id].vb, 0, vertex_size));
}
int D3DVertexBufferCache::FindBestEntry(int size)
{
// Search for buffer that fits in borders
for (int i = 0; i < _cache.Length(); i++)
{
const int vs = _cache[i].size;
if (size >= (vs - FLOAT(vs) * size_border_low) && size <= vs)
return i;
}
bool less_than_all = true;
for (int i = 0; i < _cache.Length(); i++)
{
const int vs = _cache[i].size;
if (size >= (vs - FLOAT(vs) * size_border_low))
less_than_all = false;
}
// Requested size is too small to reuse in any buffer
if (less_than_all)
return -1;
// Search for buffer that can be reallocated
for (int i = 0; i < _cache.Length(); i++)
{
const int vs = _cache[i].size;
if (size <= (vs + FLOAT(vs) * size_border_high))
return i;
}
// No buffer can be reused or reallocated, create a new one
return -1;
}
bool D3DVertexBufferCache::CreateEntry(D3DDevice *d3d, CacheEntry &entry, int size)
{
assert(d3d != NULL);
if (FAILED(d3d->GetDevice()->CreateVertexBuffer(size, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY,
0, D3DPOOL_DEFAULT, &entry.vb, NULL)))
{
return false;
}
entry.size = size;
return true;
}
void D3DVertexBufferCache::DeleteEntry(int id)
{
if (id < 0 || id >= _cache.Length())
return;
assert(_cache[id].vb != NULL);
_cache[id].vb->Release();
_cache.Replace(id);
}
bool D3DVertexBufferCache::InsertData(CacheEntry &entry, BYTE *data, int size)
{
BYTE *ptr = NULL;
if (FAILED(entry.vb->Lock(0, size, (void **)&ptr, D3DLOCK_DISCARD)))
return false;
CopyMemory(ptr, data, size);
return SUCCEEDED(entry.vb->Unlock());
}

View File

@ -0,0 +1,60 @@
#ifndef __EVAS_DIRECT3D_VERTEX_BUFFER_CACHE_H__
#define __EVAS_DIRECT3D_VERTEX_BUFFER_CACHE_H__
#include "evas_engine.h"
#include "ref.h"
#include "array.h"
class D3DDevice;
class D3DVertexBufferCache : virtual public Referenc
{
public:
struct CacheEntryInfo
{
int id;
};
public:
~D3DVertexBufferCache();
static D3DVertexBufferCache *Current();
static void SetCurrent(D3DVertexBufferCache *obj);
inline void SetSizeBorders(FLOAT low, FLOAT high);
bool InitBuffer(D3DDevice *d3d, BYTE *data, int size, CacheEntryInfo &info);
bool SelectBufferToDevice(D3DDevice *device, int id, int vertex_size);
void Uninitialize();
private:
struct CacheEntry
{
LPDIRECT3DVERTEXBUFFER9 vb;
int size;
};
private:
D3DVertexBufferCache();
int FindBestEntry(int size);
bool CreateEntry(D3DDevice *d3d, CacheEntry &entry, int size);
void DeleteEntry(int id);
bool InsertData(CacheEntry &entry, BYTE *data, int size);
private:
TArray<CacheEntry> _cache;
FLOAT size_border_low;
FLOAT size_border_high;
static Ref<D3DVertexBufferCache> _this;
};
void D3DVertexBufferCache::SetSizeBorders(FLOAT low, FLOAT high)
{
size_border_low = low;
size_border_high = high;
}
#endif // __EVAS_DIRECT3D_VERTEX_BUFFER_CACHE_H__

View File

@ -2,73 +2,44 @@
#include "evas_private.h"
#include "Evas_Engine_Direct3D.h"
#undef EAPI
#define EAPI __declspec(dllexport)
/* engine struct data */
typedef struct _Render_Engine Render_Engine;
struct _Render_Engine
{
Tilebuf *tb;
Outbuf *ob;
Tilebuf_Rect *rects;
Eina_Inlist *cur_rect;
int end : 1;
Direct3DDeviceHandler d3d;
int width, height;
int end : 1;
int in_redraw : 1;
};
/* function tables - filled in later (func and parent func) */
static Evas_Func func, pfunc;
/* prototypes we will use here */
static void *_output_setup(int width,
int height,
int rotation,
HWND window,
LPDIRECT3D9 object,
LPDIRECT3DDEVICE9 device,
LPD3DXSPRITE sprite,
LPDIRECT3DTEXTURE9 texture,
int w_depth);
//////////////////////////////////////////////////////////////////////////////
// Prototypes
static void *eng_info(Evas *e);
static void eng_info_free(Evas *e,
void *info);
static void eng_setup(Evas *e,
void *info);
static void eng_info_free(Evas *e, void *info);
static void eng_setup(Evas *e, void *info);
static void eng_output_free(void *data);
static void eng_output_resize(void *data,
int width,
int height);
static void eng_output_tile_size_set(void *data,
int width,
int height);
static void eng_output_redraws_rect_add(void *data,
int x,
int y,
int width,
int height);
static void eng_output_redraws_rect_del(void *data,
int x,
int y,
int width,
int height);
static void eng_output_redraws_clear(void *data);
static void eng_output_resize(void *data, int width, int height);
//////////////////////////////////////////////////////////////////////////////
// Init / shutdown methods
//
/* internal engine routines */
static void *
_output_setup(int width,
int height,
int rotation,
HWND window,
LPDIRECT3D9 object,
LPDIRECT3DDEVICE9 device,
LPD3DXSPRITE sprite,
LPDIRECT3DTEXTURE9 texture,
int w_depth)
_output_setup(int width, int height, int rotation, HWND window, int depth, int fullscreen)
{
Render_Engine *re;
re = (Render_Engine *)calloc(1, sizeof(Render_Engine));
if (!re) return NULL;
if (!re)
return NULL;
/* if we haven't initialized - init (automatic abort if already done) */
evas_common_cpu_init();
@ -85,247 +56,460 @@ _output_setup(int width,
evas_common_draw_init();
evas_common_tilebuf_init();
evas_direct3d_outbuf_init();
/* get any stored performance metrics from device */
re->ob = evas_direct3d_outbuf_setup_d3d(width, height, rotation, OUTBUF_DEPTH_INHERIT, window, object, device, sprite, texture, w_depth);
if (!re->ob)
if ((re->d3d = evas_direct3d_init(window, depth, fullscreen)) == 0)
{
free(re);
return NULL;
free(re);
return NULL;
}
re->tb = evas_common_tilebuf_new(width, height);
if (!re->tb)
{
evas_direct3d_outbuf_free(re->ob);
free(re);
return NULL;
}
/* FIXME: that comment :) */
/* in preliminary tests 16x16 gave highest framerates */
evas_common_tilebuf_set_tile_size(re->tb, TILESIZE, TILESIZE);
re->width = width;
re->height = height;
return re;
}
/* engine api this module provides */
static void *
eng_info(Evas *e)
{
Evas_Engine_Info_Direct3D *info;
info = (Evas_Engine_Info_Direct3D *)calloc(1, sizeof(Evas_Engine_Info_Direct3D));
if (!info) return NULL;
info->magic.magic = rand();
memset(&info->info, 0, sizeof(info->info));
return info;
e = NULL;
}
static void
eng_info_free(Evas *e,
void *info)
eng_info_free(Evas *e, void *info)
{
Evas_Engine_Info_Direct3D *in;
in = (Evas_Engine_Info_Direct3D *)info;
free(in);
}
static void
eng_setup(Evas *e,
void *info)
eng_setup(Evas *e, void *info)
{
Render_Engine *re;
Render_Engine *re;
Evas_Engine_Info_Direct3D *in;
re = (Render_Engine *)e->engine.data.output;
in = (Evas_Engine_Info_Direct3D *)info;
if (!e->engine.data.output)
e->engine.data.output =
_output_setup(e->output.w,
e->output.h,
in->info.rotation,
in->info.window,
in->info.object,
in->info.device,
in->info.sprite,
in->info.texture,
in->info.depth);
if (!e->engine.data.output) return;
if (!e->engine.data.context)
e->engine.data.context =
e->engine.func->context_new(e->engine.data.output);
if (e->engine.data.output == NULL)
{
e->engine.data.output = _output_setup(e->output.w, e->output.h,
in->info.rotation, in->info.window, in->info.depth, in->info.fullscreen);
}
else if (in->info.fullscreen != 0)
{
if (re != NULL)
evas_direct3d_set_layered(re->d3d, 0, 0, 0, NULL);
evas_direct3d_set_fullscreen(re->d3d, -1, -1, 1);
}
else if (in->info.fullscreen == 0)
{
evas_direct3d_set_fullscreen(re->d3d, re->width, re->height, 0);
if (re != NULL && in->info.layered == 0)
evas_direct3d_set_layered(re->d3d, 0, 0, 0, NULL);
else if (re != NULL && in->info.layered != 0 && in->shape != NULL)
evas_direct3d_set_layered(re->d3d, 1, in->shape->width, in->shape->height, in->shape->mask);
}
if (e->engine.data.output == NULL)
return;
if (e->engine.data.context == NULL)
e->engine.data.context = e->engine.func->context_new(e->engine.data.output);
re = (Render_Engine *)e->engine.data.output;
}
static void
eng_output_free(void *data)
{
Render_Engine *re;
Render_Engine *re = (Render_Engine *)data;
evas_direct3d_free(re->d3d);
re = (Render_Engine *)data;
evas_direct3d_outbuf_free(re->ob);
evas_common_tilebuf_free(re->tb);
if (re->rects) evas_common_tilebuf_free_render_rects(re->rects);
free(re);
evas_common_font_shutdown();
evas_common_image_shutdown();
}
static void
eng_output_resize(void *data,
int width,
int height)
{
Render_Engine *re;
//////////////////////////////////////////////////////////////////////////////
// Context
//
re = (Render_Engine *)data;
evas_direct3d_outbuf_reconfigure(re->ob,
width,
height,
evas_direct3d_outbuf_rot_get(re->ob),
OUTBUF_DEPTH_INHERIT);
evas_common_tilebuf_free(re->tb);
re->tb = evas_common_tilebuf_new(width, height);
if (re->tb)
evas_common_tilebuf_set_tile_size(re->tb, TILESIZE, TILESIZE);
static void
eng_context_color_set(void *data, void *context, int r, int g, int b, int a)
{
Render_Engine *re = (Render_Engine *)data;
evas_direct3d_context_color_set(re->d3d, r, g, b, a);
evas_common_draw_context_set_color(context, r, g, b, a);
}
static void
eng_output_tile_size_set(void *data,
int width,
int height)
eng_context_multiplier_set(void *data, void *context, int r, int g, int b, int a)
{
Render_Engine *re;
Render_Engine *re = (Render_Engine *)data;
evas_direct3d_context_set_multiplier(re->d3d, 255, 255, 255, a);
re = (Render_Engine *)data;
evas_common_tilebuf_set_tile_size(re->tb, width, height);
evas_common_draw_context_set_multiplier(context, r, g, b, a);
}
static void
eng_output_redraws_rect_add(void *data,
int x,
int y,
int width,
int height)
eng_context_multiplier_unset(void *data, void *context)
{
Render_Engine *re;
Render_Engine *re = (Render_Engine *)data;
evas_direct3d_context_set_multiplier(re->d3d, 255, 255, 255, 255);
re = (Render_Engine *)data;
evas_common_tilebuf_add_redraw(re->tb, x, y, width, height);
evas_common_draw_context_unset_multiplier(context);
}
//////////////////////////////////////////////////////////////////////////////
// Output manipulating
//
static void
eng_output_resize(void *data, int width, int height)
{
Render_Engine *re = (Render_Engine *)data;
re->width = width;
re->height = height;
evas_direct3d_resize(re->d3d, width, height);
}
static void
eng_output_redraws_rect_del(void *data,
int x,
int y,
int width,
int height)
eng_output_redraws_rect_add(void *data, int x, int y, int width, int height)
{
Render_Engine *re;
Render_Engine *re = (Render_Engine *)data;
}
re = (Render_Engine *)data;
evas_common_tilebuf_del_redraw(re->tb, x, y, width, height);
static void
eng_output_redraws_rect_del(void *data, int x, int y, int width, int height)
{
Render_Engine *re = (Render_Engine *)data;
}
static void
eng_output_redraws_clear(void *data)
{
Render_Engine *re;
re = (Render_Engine *)data;
evas_common_tilebuf_clear(re->tb);
Render_Engine *re = (Render_Engine *)data;
}
static void *
eng_output_redraws_next_update_get(void *data,
int *x,
int *y,
int *w,
int *h,
int *cx,
int *cy,
int *cw,
int *ch)
eng_output_redraws_next_update_get(void *data, int *x, int *y, int *w, int *h,
int *cx, int *cy, int *cw, int *ch)
{
Render_Engine *re;
RGBA_Image *surface;
Tilebuf_Rect *rect;
int ux;
int uy;
int uw;
int uh;
re = (Render_Engine *)data;
if (re->end)
{
re->end = 0;
return NULL;
}
if (!re->rects)
{
re->rects = evas_common_tilebuf_get_render_rects(re->tb);
re->cur_rect = EINA_INLIST_GET(re->rects);
}
if (!re->cur_rect) return NULL;
rect = (Tilebuf_Rect *)re->cur_rect;
ux = rect->x; uy = rect->y; uw = rect->w; uh = rect->h;
re->cur_rect = re->cur_rect->next;
if (!re->cur_rect)
{
evas_common_tilebuf_free_render_rects(re->rects);
re->rects = NULL;
re->end = 1;
re->end = 0;
re->in_redraw = 0;
return NULL;
}
surface = evas_direct3d_outbuf_new_region_for_update(re->ob,
ux, uy,
uw, uh,
cx, cy,
cw, ch);
*x = ux; *y = uy; *w = uw; *h = uh;
if (x) *x = 0;
if (y) *y = 0;
if (w) *w = 800; //re->d3d.width;
if (h) *h = 600; //re->d3d.height;
if (cx) *cx = 0;
if (cy) *cy = 0;
if (cw) *cw = 800; //re->d3d.width;
if (ch) *ch = 600; //re->d3d.height;
return surface;
re->in_redraw = 1;
return re;
}
static void
eng_output_redraws_next_update_push(void *data,
void *surface,
int x,
int y,
int w,
int h)
eng_output_redraws_next_update_push(void *data, void *surface,
int x, int y, int w, int h)
{
Render_Engine *re;
re = (Render_Engine *)data;
evas_common_pipe_begin((RGBA_Image *)surface);
evas_common_pipe_flush((RGBA_Image *)surface);
evas_direct3d_outbuf_push_updated_region(re->ob, (RGBA_Image *)surface, x, y, w, h);
evas_direct3d_outbuf_free_region_for_update(re->ob, (RGBA_Image *)surface);
evas_common_cpu_end_opt();
Render_Engine *re = (Render_Engine *)data;
re->end = 1;
}
static void
eng_output_flush(void *data)
{
Render_Engine *re;
re = (Render_Engine *)data;
evas_direct3d_outbuf_flush(re->ob);
Render_Engine *re = (Render_Engine *)data;
evas_direct3d_render_all(re->d3d);
}
static void
eng_output_idle_flush(void *data)
{
Render_Engine *re;
re = (Render_Engine *)data;
Render_Engine *re = (Render_Engine *)data;
}
//////////////////////////////////////////////////////////////////////////////
// Draw objects
//
static void
eng_line_draw(void *data, void *context, void *surface, int x1, int y1, int x2, int y2)
{
Render_Engine *re = (Render_Engine *)data;
if (re->in_redraw == 0)
return;
evas_direct3d_line_draw(re->d3d, x1, y1, x2, y2);
}
static void
eng_rectangle_draw(void *data, void *context, void *surface, int x, int y, int w, int h)
{
Render_Engine *re = (Render_Engine *)data;
if (re->in_redraw == 0)
return;
evas_direct3d_rectangle_draw(re->d3d, x, y, w, h);
}
static void *
eng_image_load(void *data, const char *file, const char *key, int *error, Evas_Image_Load_Opts *lo)
{
Render_Engine *re = (Render_Engine *)data;
*error = 0;
return evas_direct3d_image_load(re->d3d, file, key, NULL, lo);
}
static void *
eng_image_new_from_data(void *data, int w, int h, DATA32 *image_data, int alpha, int cspace)
{
Render_Engine *re = (Render_Engine *)data;
return evas_direct3d_image_new_from_data(re->d3d, w, h, image_data, alpha, cspace);
}
static void *
eng_image_new_from_copied_data(void *data, int w, int h, DATA32 *image_data, int alpha, int cspace)
{
Render_Engine *re = (Render_Engine *)data;
return evas_direct3d_image_new_from_copied_data(re->d3d, w, h, image_data, alpha, cspace);
}
static void
eng_image_free(void *data, void *image)
{
Render_Engine *re = (Render_Engine *)data;
evas_direct3d_image_free(re->d3d, image);
}
static void *
eng_image_data_put(void *data, void *image, DATA32 *image_data)
{
Render_Engine *re = (Render_Engine *)data;
evas_direct3d_image_data_put(re->d3d, image, image_data);
return image;
}
static void *
eng_image_dirty_region(void *data, void *image, int x, int y, int w, int h)
{
return image;
}
static void *
eng_image_data_get(void *data, void *image, int to_write, DATA32 **image_data)
{
Render_Engine *re = (Render_Engine *)data;
evas_direct3d_image_data_get(re->d3d, image, to_write, image_data);
return image;
}
static void
eng_image_draw(void *data, void *context, void *surface, void *image,
int src_x, int src_y, int src_w, int src_h,
int dst_x, int dst_y, int dst_w, int dst_h, int smooth)
{
Render_Engine *re = (Render_Engine *)data;
evas_direct3d_image_draw(re->d3d, image,
src_x, src_y, src_w, src_h,
dst_x, dst_y, dst_w, dst_h, smooth);
}
static void
eng_image_size_get(void *data, void *image, int *w, int *h)
{
evas_direct3d_image_size_get(image, w, h);
}
static int
eng_image_alpha_get(void *data, void *image)
{
// Hm:)
if (!image)
return 1;
return 0;
}
static int
eng_image_colorspace_get(void *data, void *image)
{
// Well, change that when you think about other colorspace
return EVAS_COLORSPACE_ARGB8888;
}
static void *
eng_image_border_set(void *data, void *image, int l, int r, int t, int b)
{
Render_Engine *re = (Render_Engine *)data;
evas_direct3d_image_border_set(re->d3d, image, l, t, r, b);
return image;
}
static void
eng_image_border_get(void *data, void *image, int *l, int *r, int *t, int *b)
{
Render_Engine *re = (Render_Engine *)data;
evas_direct3d_image_border_get(re->d3d, image, l, t, r, b);
}
static void
eng_font_draw(void *data, void *context, void *surface, void *font, int x, int y, int w, int h, int ow, int oh, const char *text)
{
Render_Engine *re = (Render_Engine *)data;
RGBA_Image im;
im.image.data = NULL;
im.cache_entry.w = re->width;
im.cache_entry.h = re->height;
evas_direct3d_select_or_create_font(re->d3d, font);
evas_common_draw_context_font_ext_set(context, re->d3d,
evas_direct3d_font_texture_new,
evas_direct3d_font_texture_free,
evas_direct3d_font_texture_draw);
evas_common_font_draw(&im, context, font, x, y, text);
evas_common_draw_context_font_ext_set(context, NULL, NULL, NULL, NULL);
}
static void
eng_font_free(void *data, void *font)
{
Render_Engine *re = (Render_Engine *)data;
evas_common_font_free(font);
evas_direct3d_font_free(re->d3d, font);
}
//////////////////////////////////////////////////////////////////////////////
// Gradients
//
static void
eng_gradient2_color_np_stop_insert(void *data, void *gradient, int r, int g, int b, int a, float pos)
{
}
static void
eng_gradient2_clear(void *data, void *gradient)
{
}
static void
eng_gradient2_fill_transform_set(void *data, void *gradient, void *transform)
{
}
static void
eng_gradient2_fill_spread_set(void *data, void *gradient, int spread)
{
}
static void *
eng_gradient2_linear_new(void *data)
{
return NULL;
}
static void
eng_gradient2_linear_free(void *data, void *linear_gradient)
{
}
static void
eng_gradient2_linear_fill_set(void *data, void *linear_gradient, int x0, int y0, int x1, int y1)
{
}
static int
eng_gradient2_linear_is_opaque(void *data, void *context, void *linear_gradient, int x, int y, int w, int h)
{
return 1;
}
static int
eng_gradient2_linear_is_visible(void *data, void *context, void *linear_gradient, int x, int y, int w, int h)
{
return 1;
}
static void
eng_gradient2_linear_render_pre(void *data, void *context, void *linear_gradient)
{
}
static void
eng_gradient2_linear_render_post(void *data, void *linear_gradient)
{
}
static void
eng_gradient2_linear_draw(void *data, void *context, void *surface, void *linear_gradient, int x, int y, int w, int h)
{
}
static void *
eng_gradient2_radial_new(void *data)
{
return NULL;
}
static void
eng_gradient2_radial_free(void *data, void *radial_gradient)
{
}
static void
eng_gradient2_radial_fill_set(void *data, void *radial_gradient, float cx, float cy, float rx, float ry)
{
}
static int
eng_gradient2_radial_is_opaque(void *data, void *context, void *radial_gradient, int x, int y, int w, int h)
{
return 1;
}
static int
eng_gradient2_radial_is_visible(void *data, void *context, void *radial_gradient, int x, int y, int w, int h)
{
return 1;
}
static void
eng_gradient2_radial_render_pre(void *data, void *context, void *radial_gradient)
{
}
static void
eng_gradient2_radial_render_post(void *data, void *radial_gradient)
{
}
static void
eng_gradient2_radial_draw(void *data, void *context, void *surface, void *radial_gradient, int x, int y, int w, int h)
{
}
/* module advertising code */
EAPI int
module_open(Evas_Module *em)
@ -340,9 +524,11 @@ module_open(Evas_Module *em)
ORD(info);
ORD(info_free);
ORD(setup);
ORD(context_color_set);
ORD(context_multiplier_set);
ORD(context_multiplier_unset);
ORD(output_free);
ORD(output_resize);
ORD(output_tile_size_set);
ORD(output_redraws_rect_add);
ORD(output_redraws_rect_del);
ORD(output_redraws_clear);
@ -350,6 +536,45 @@ module_open(Evas_Module *em)
ORD(output_redraws_next_update_push);
ORD(output_flush);
ORD(output_idle_flush);
ORD(line_draw);
ORD(rectangle_draw);
ORD(image_load);
ORD(image_new_from_data);
ORD(image_new_from_copied_data);
ORD(image_free);
ORD(image_data_put);
ORD(image_dirty_region);
ORD(image_data_get);
ORD(image_draw);
ORD(image_size_get);
ORD(image_alpha_get);
ORD(image_colorspace_get);
ORD(image_border_set);
ORD(image_border_get);
ORD(font_draw);
ORD(font_free);
/*
ORD(gradient2_color_np_stop_insert);
ORD(gradient2_clear);
ORD(gradient2_fill_transform_set);
ORD(gradient2_fill_spread_set);
ORD(gradient2_linear_new);
ORD(gradient2_linear_free);
ORD(gradient2_linear_fill_set);
ORD(gradient2_linear_is_opaque);
ORD(gradient2_linear_is_visible);
ORD(gradient2_linear_render_pre);
ORD(gradient2_linear_render_post);
ORD(gradient2_linear_draw);
ORD(gradient2_radial_new);
ORD(gradient2_radial_free);
ORD(gradient2_radial_fill_set);
ORD(gradient2_radial_is_opaque);
ORD(gradient2_radial_is_visible);
ORD(gradient2_radial_render_pre);
ORD(gradient2_radial_render_post);
ORD(gradient2_radial_draw);
*/
/* now advertise out own api */
em->functions = (void *)(&func);
return 1;
@ -363,7 +588,7 @@ module_close(void)
EAPI Evas_Module_Api evas_modapi =
{
EVAS_MODULE_API_VERSION,
EVAS_MODULE_TYPE_ENGINE,
"direct3d",
"none"
EVAS_MODULE_TYPE_ENGINE,
"direct3d",
"none"
};

View File

@ -6,132 +6,87 @@
#include <d3d9.h>
#include <d3dx9.h>
#ifdef __cplusplus
extern "C" {
#endif
#define EVAS_INLINE_ARRAY_H // We dont need that and it is buggy
#include "evas_common.h"
#include "evas_private.h"
#ifdef __cplusplus
}
#endif
typedef struct _Outbuf Outbuf;
typedef struct _Direct3D_Output_Buffer Direct3D_Output_Buffer;
enum _Outbuf_Depth
{
OUTBUF_DEPTH_NONE,
OUTBUF_DEPTH_INHERIT,
OUTBUF_DEPTH_RGB_16BPP_565_565_DITHERED,
OUTBUF_DEPTH_RGB_16BPP_555_555_DITHERED,
OUTBUF_DEPTH_RGB_16BPP_444_444_DITHERED,
OUTBUF_DEPTH_RGB_16BPP_565_444_DITHERED,
OUTBUF_DEPTH_RGB_32BPP_888_8888,
OUTBUF_DEPTH_LAST
};
typedef enum _Outbuf_Depth Outbuf_Depth;
struct _Outbuf
{
int width;
int height;
int rot;
Outbuf_Depth depth;
struct {
struct {
HWND window;
LPDIRECT3D9 object;
LPDIRECT3DDEVICE9 device;
LPD3DXSPRITE sprite;
LPDIRECT3DTEXTURE9 texture;
int depth;
} d3d;
struct {
DATA32 r, g, b;
} mask;
/* a list of pending regions to write to the target */
Eina_List *pending_writes;
} priv;
};
struct _Direct3D_Output_Buffer
{
void *image;
int x;
int y;
int width;
int height;
int depth;
int pitch;
};
//#define ENABLE_LOG_PRINTF
#ifdef ENABLE_LOG_PRINTF
#define Log(str, ...) printf("D3D "str"\n", __VA_ARGS__)
#else
#define Log(str, ...)
#endif
typedef void * Direct3DDeviceHandler;
typedef void * Direct3DImageHandler;
typedef void * Direct3DFontGlyphHandler;
#ifdef __cplusplus
extern "C" {
#endif
// Main engine functions
/* Outbuf functions */
void evas_direct3d_outbuf_init(void);
void evas_direct3d_outbuf_free(Outbuf *buf);
Outbuf *evas_direct3d_outbuf_setup_d3d(int width,
int height,
int rotation,
Outbuf_Depth depth,
HWND window,
LPDIRECT3D9 object,
LPDIRECT3DDEVICE9 device,
LPD3DXSPRITE sprite,
LPDIRECT3DTEXTURE9 texture,
int w_depth);
RGBA_Image *evas_direct3d_outbuf_new_region_for_update(Outbuf *buf,
int x,
int y,
int width,
int height,
int *cx,
int *cy,
int *cw,
int *ch);
void evas_direct3d_outbuf_free_region_for_update(Outbuf *buf,
RGBA_Image *update);
void evas_direct3d_outbuf_flush(Outbuf *buf);
void evas_direct3d_outbuf_push_updated_region(Outbuf *buf,
RGBA_Image *update,
int x,
int y,
int width,
int height);
void evas_direct3d_outbuf_reconfigure(Outbuf *buf,
int width,
int height,
int rotation,
Outbuf_Depth depth);
int evas_direct3d_outbuf_width_get(Outbuf *buf);
int evas_direct3d_outbuf_height_get(Outbuf *buf);
Outbuf_Depth evas_direct3d_outbuf_depth_get(Outbuf *buf);
int evas_direct3d_outbuf_rot_get(Outbuf *buf);
/* Output Buffer functions */
Direct3D_Output_Buffer *evas_direct3d_output_buffer_new(int depth,
int width,
int height,
void *data);
void evas_direct3d_output_buffer_free(Direct3D_Output_Buffer *d3dob);
void evas_direct3d_output_buffer_paste(Direct3D_Output_Buffer *d3dob,
DATA8 *d3d_data,
int d3d_width,
int d3d_height,
int d3d_pitch,
int x,
int y);
DATA8 *evas_direct3d_output_buffer_data(Direct3D_Output_Buffer *d3dob,
int *bytes_per_line_ret);
int evas_direct3d_output_buffer_depth(Direct3D_Output_Buffer *d3dob);
Direct3DDeviceHandler evas_direct3d_init(HWND window, int depth, int fullscreen);
void evas_direct3d_free(Direct3DDeviceHandler d3d);
void evas_direct3d_render_all(Direct3DDeviceHandler d3d);
void evas_direct3d_resize(Direct3DDeviceHandler d3d, int width, int height);
void evas_direct3d_set_fullscreen(Direct3DDeviceHandler d3d,
int width, int height, int fullscreen);
void evas_direct3d_set_layered(Direct3DDeviceHandler d3d, int layered,
int mask_width, int mask_height, unsigned char *mask);
int evas_direct3d_masks_get(Outbuf *buf);
void *evas_direct3d_lock(Outbuf *buf, int *d3d_width, int *d3d_height, int *d3d_pitch);
void evas_direct3d_unlock(Outbuf *buf);
// Context manipulations
void evas_direct3d_context_color_set(Direct3DDeviceHandler d3d, int r, int g, int b, int a);
void evas_direct3d_context_set_multiplier(Direct3DDeviceHandler d3d, int r, int g, int b, int a);
// Simple objects
void evas_direct3d_line_draw(Direct3DDeviceHandler d3d, int x1, int y1, int x2, int y2);
void evas_direct3d_rectangle_draw(Direct3DDeviceHandler d3d, int x, int y, int w, int h);
// Images
Direct3DImageHandler evas_direct3d_image_load(Direct3DDeviceHandler d3d,
const char *file, const char *key, int *error, Evas_Image_Load_Opts *lo);
Direct3DImageHandler evas_direct3d_image_new_from_data(Direct3DDeviceHandler d3d,
int w, int h, DWORD *image_data, int alpha, int cspace);
Direct3DImageHandler evas_direct3d_image_new_from_copied_data(Direct3DDeviceHandler d3d,
int w, int h, DWORD *image_data, int alpha, int cspace);
void evas_direct3d_image_free(Direct3DDeviceHandler d3d, Direct3DImageHandler image);
void evas_direct3d_image_data_put(Direct3DDeviceHandler d3d, Direct3DImageHandler image,
DWORD *image_data);
void evas_direct3d_image_data_get(Direct3DDeviceHandler d3d, Direct3DImageHandler image,
int to_write, DATA32 **image_data);
void evas_direct3d_image_draw(Direct3DDeviceHandler d3d, Direct3DImageHandler image,
int src_x, int src_y, int src_w, int src_h,
int dst_x, int dst_y, int dst_w, int dst_h, int smooth);
void evas_direct3d_image_size_get(Direct3DImageHandler image, int *w, int *h);
void evas_direct3d_image_border_set(Direct3DDeviceHandler d3d, Direct3DImageHandler image,
int l, int r, int t, int b);
void evas_direct3d_image_border_get(Direct3DDeviceHandler d3d, Direct3DImageHandler image,
int *l, int *r, int *t, int *b);
// Fonts
Direct3DFontGlyphHandler evas_direct3d_font_texture_new(Direct3DDeviceHandler d3d,
RGBA_Font_Glyph *fg);
void evas_direct3d_font_texture_free(Direct3DFontGlyphHandler ft);
void evas_direct3d_font_texture_draw(Direct3DDeviceHandler d3d, void *dest, void *context,
RGBA_Font_Glyph *fg, int x, int y);
void evas_direct3d_select_or_create_font(Direct3DDeviceHandler d3d, void *font);
void evas_direct3d_font_free(Direct3DDeviceHandler d3d, void *font);
#ifdef __cplusplus
}

View File

@ -1,328 +0,0 @@
#include "evas_engine.h"
void
evas_direct3d_outbuf_init(void)
{
}
void
evas_direct3d_outbuf_free(Outbuf *buf)
{
free(buf);
}
Outbuf *
evas_direct3d_outbuf_setup_d3d(int width,
int height,
int rotation,
Outbuf_Depth depth,
HWND window,
LPDIRECT3D9 object,
LPDIRECT3DDEVICE9 device,
LPD3DXSPRITE sprite,
LPDIRECT3DTEXTURE9 texture,
int w_depth)
{
Outbuf *buf;
buf = (Outbuf *)calloc(1, sizeof(Outbuf));
if (!buf)
return NULL;
buf->width = width;
buf->height = height;
buf->depth = depth;
buf->rot = rotation;
buf->priv.d3d.window = window;
buf->priv.d3d.object = object;
buf->priv.d3d.device = device;
buf->priv.d3d.sprite = sprite;
buf->priv.d3d.texture = texture;
buf->priv.d3d.depth = w_depth;
{
Gfx_Func_Convert conv_func;
Direct3D_Output_Buffer *d3dob;
d3dob = evas_direct3d_output_buffer_new(buf->priv.d3d.depth, 1, 1, NULL);
conv_func = NULL;
if (d3dob)
{
if (evas_direct3d_masks_get(buf))
{
if ((rotation == 0) || (rotation == 180))
conv_func = evas_common_convert_func_get(0,
width,
height,
evas_direct3d_output_buffer_depth (d3dob),
buf->priv.mask.r,
buf->priv.mask.g,
buf->priv.mask.b,
PAL_MODE_NONE,
rotation);
else if ((rotation == 90) || (rotation == 270))
conv_func = evas_common_convert_func_get(0,
height,
width,
evas_direct3d_output_buffer_depth (d3dob),
buf->priv.mask.r,
buf->priv.mask.g,
buf->priv.mask.b,
PAL_MODE_NONE,
rotation);
}
evas_direct3d_output_buffer_free(d3dob);
if (!conv_func)
{
printf(".[ Evas Error ].\n"
" {\n"
" At depth %i:\n"
" RGB format mask: %08x, %08x, %08x\n"
" Not supported by and compiled in converters!\n"
" }\n",
buf->priv.d3d.depth,
buf->priv.mask.r,
buf->priv.mask.g,
buf->priv.mask.b);
}
}
}
return buf;
}
RGBA_Image *
evas_direct3d_outbuf_new_region_for_update(Outbuf *buf,
int x,
int y,
int width,
int height,
int *cx,
int *cy,
int *cw,
int *ch)
{
RGBA_Image *im;
Direct3D_Output_Buffer *d3dob = NULL;
int bpl = 0;
*cx = 0;
*cy = 0;
*cw = width;
*ch = height;
if ((buf->rot == 0) &&
(buf->priv.mask.r == 0xff0000) &&
(buf->priv.mask.g == 0x00ff00) &&
(buf->priv.mask.b == 0x0000ff))
{
im = evas_cache_image_empty(evas_common_image_cache_get());
im->image->w = width;
im->image->h = height;
im->image->data = NULL;
im->image->no_free = 1;
d3dob = evas_direct3d_output_buffer_new(buf->priv.d3d.depth,
width,
height,
NULL);
im->extended_info = d3dob;
im->image->data = (DATA32 *)evas_direct3d_output_buffer_data(d3dob, &bpl);
}
else
{
im = (RGBA_Image*) evas_cache_image_empty(evas_common_image_cache_get());
evas_cache_image_surface_alloc(&im->cache_entry, width, height);
im->extended_info = d3dob;
if ((buf->rot == 0) || (buf->rot == 180))
d3dob = evas_direct3d_output_buffer_new(buf->priv.d3d.depth,
width,
height,
NULL);
else if ((buf->rot == 90) || (buf->rot == 270))
d3dob = evas_direct3d_output_buffer_new(buf->priv.d3d.depth,
width,
height,
NULL);
im->extended_info = d3dob;
}
buf->priv.pending_writes = eina_list_append(buf->priv.pending_writes, im);
return im;
}
void
evas_direct3d_outbuf_free_region_for_update(Outbuf *buf,
RGBA_Image *update)
{
/* no need to do anything - they are cleaned up on flush */
}
void
evas_direct3d_outbuf_flush(Outbuf *buf)
{
Eina_List *l;
void *d3d_data;
int d3d_width;
int d3d_height;
int d3d_pitch;
RGBA_Image *im;
Direct3D_Output_Buffer *d3dob;
/* lock the texture */
if (!(d3d_data = evas_direct3d_lock(buf,
&d3d_width, &d3d_height, &d3d_pitch)))
goto free_images;
/* copy safely the images that need to be drawn onto the back surface */
EINA_LIST_FOREACH(buf->priv.pending_writes, l, im)
{
d3dob = im->extended_info;
/* paste now */
evas_direct3d_output_buffer_paste(d3dob,
d3d_data,
d3d_width,
d3d_height,
d3d_pitch,
d3dob->x,
d3dob->y);
}
/* unlock the texture */
evas_direct3d_unlock(buf);
free_images:
while (buf->priv.pending_writes)
{
im = buf->priv.pending_writes->data;
buf->priv.pending_writes = eina_list_remove_list(buf->priv.pending_writes,
buf->priv.pending_writes);
d3dob = im->extended_info;
evas_cache_image_drop(im);
if (d3dob) evas_direct3d_output_buffer_free(d3dob);
}
evas_common_cpu_end_opt();
}
void
evas_direct3d_outbuf_push_updated_region(Outbuf *buf,
RGBA_Image *update,
int x,
int y,
int width,
int height)
{
Gfx_Func_Convert conv_func;
Direct3D_Output_Buffer *d3dob;
DATA32 *src_data;
void *data;
int bpl = 0;
conv_func = NULL;
d3dob = update->extended_info;
if ((buf->rot == 0) || (buf->rot == 180))
conv_func = evas_common_convert_func_get(NULL,
width,
height,
evas_direct3d_output_buffer_depth(d3dob),
buf->priv.mask.r,
buf->priv.mask.g,
buf->priv.mask.b,
PAL_MODE_NONE,
buf->rot);
else if ((buf->rot == 90) || (buf->rot == 270))
conv_func = evas_common_convert_func_get(NULL,
height,
width,
evas_direct3d_output_buffer_depth(d3dob),
buf->priv.mask.r,
buf->priv.mask.g,
buf->priv.mask.b,
PAL_MODE_NONE,
buf->rot);
if (!conv_func) return;
data = evas_direct3d_output_buffer_data(d3dob, &bpl);
src_data = update->image->data;
if (buf->rot == 0)
{
d3dob->x = x;
d3dob->y = y;
}
else if (buf->rot == 90)
{
d3dob->x = y;
d3dob->y = buf->width - x - width;
}
else if (buf->rot == 180)
{
d3dob->x = buf->width - x - width;
d3dob->y = buf->height - y - height;
}
else if (buf->rot == 270)
{
d3dob->x = buf->height - y - height;
d3dob->y = x;
}
if ((buf->rot == 0) || (buf->rot == 180))
{
d3dob->width = width;
d3dob->height = height;
}
else if ((buf->rot == 90) || (buf->rot == 270))
{
d3dob->width = height;
d3dob->height = width;
}
if (data != src_data)
conv_func(src_data, data,
0,
bpl /
((evas_direct3d_output_buffer_depth(d3dob))) - d3dob->width,
d3dob->width, d3dob->height, x, y, NULL);
}
void
evas_direct3d_outbuf_reconfigure(Outbuf *buf,
int width,
int height,
int rotation,
Outbuf_Depth depth)
{
if ((width == buf->width) && (height == buf->height) &&
(rotation == buf->rot) && (depth == buf->depth))
return;
buf->width = width;
buf->height = height;
buf->rot = rotation;
}
int
evas_direct3d_outbuf_width_get(Outbuf *buf)
{
return buf->width;
}
int
evas_direct3d_outbuf_height_get(Outbuf *buf)
{
return buf->height;
}
Outbuf_Depth
evas_direct3d_outbuf_depth_get(Outbuf *buf)
{
return buf->depth;
}
int
evas_direct3d_outbuf_rot_get(Outbuf *buf)
{
return buf->rot;
}

View File

@ -0,0 +1,210 @@
#ifndef __REF_H__
#define __REF_H__
//////////////////////////////////////////////////////////////////////////////
// class Referenc
// Desc: Base class enabling reference interface
// Note: Class should derive as virtual
//
class Referenc
{
public:
Referenc()
: refs_count(0) {};
inline int AddRef()
{
return ++refs_count;
}
inline int RemRef()
{
return --refs_count;
}
inline int RefCount()
{
return refs_count;
}
private:
int refs_count;
};
//////////////////////////////////////////////////////////////////////////////
// template Ref
// Desc: Holder in smart-pointers system.
// Important: Only Referenc subclasses may be used as template param.
//
template <class T>
class Ref
{
public:
// Constructors & destructor
Ref();
//Ref(Ref<T> &ref);
Ref(const Ref<T> &ref);
Ref(T *ptr);
Ref(const T *ptr);
~Ref();
Ref<T> &operator =(Ref<T> &ref);
Ref<T> &operator =(T *ptr);
inline T *Addr();
inline T *Addr() const;
inline int RefCount();
inline bool IsNull();
inline T *operator ->();
inline operator const T *() const;
inline operator T *();
//private:
void RemRef();
private:
T *m_ptr;
};
//////////////////////////////////////////////////////////////////////////////
// Constructors & destructor
template <class T> Ref<T>::Ref()
: m_ptr(NULL)
{
}
//template <class T> Ref<T>::Ref(Ref<T> &ref)
//: m_ptr(NULL)
//{
// if (ref.Addr() != NULL)
// {
// m_ptr = ref.Addr();
// ((Referenc *)m_ptr)->AddRef();
// }
//}
template <class T> Ref<T>::Ref(const Ref<T> &ref)
: m_ptr(NULL)
{
if (ref.Addr() != NULL)
{
m_ptr = ref.Addr();
((Referenc *)m_ptr)->AddRef();
}
}
template <class T> Ref<T>::Ref(T *ptr)
: m_ptr(NULL)
{
if (ptr != NULL)
{
m_ptr = ptr;
((Referenc *)m_ptr)->AddRef();
}
}
template <class T> Ref<T>::Ref(const T *ptr)
: m_ptr(NULL)
{
if (ptr != NULL)
{
m_ptr = ptr;
((Referenc *)m_ptr)->AddRef();
}
}
template <class T> Ref<T>::~Ref()
{
if (m_ptr == NULL)
return;
RemRef();
}
// Check pointer on correctness
template <class T> bool Ref<T>::IsNull()
{
return (m_ptr == NULL);
}
//////////////////////////////////////////////////////////////////////////////
// Operators
template <class T> Ref<T> &Ref<T>::operator =(T *ptr)
{
if (ptr != NULL)
{
if (m_ptr != ptr)
{
RemRef();
m_ptr = ptr;
((Referenc *)m_ptr)->AddRef();
}
}
else if (m_ptr != NULL)
RemRef();
return *this;
}
template <class T> Ref<T> &Ref<T>::operator =(Ref<T> &ref)
{
if (ref.Addr() != NULL)
{
if (m_ptr != ref.Addr())
{
RemRef();
m_ptr = ref.Addr();
((Referenc *)m_ptr)->AddRef();
}
}
else if (m_ptr != NULL)
RemRef();
return *this;
}
// Get pointer
template <class T> T *Ref<T>::Addr()
{
return m_ptr;
}
template <class T> T *Ref<T>::Addr() const
{
return m_ptr;
}
// Get refs count
template <class T> int Ref<T>::RefCount()
{
if (m_ptr == NULL)
return 0;
return ((Referenc *)m_ptr)->RefCount();
}
// Remove ref to the object and delete it if necessary
// WARNING: arrays cannot be deleted
template <class T> void Ref<T>::RemRef()
{
if (m_ptr == NULL)
return;
if (((Referenc *)m_ptr)->RemRef() == 0)
delete m_ptr;
m_ptr = NULL;
}
template <class T> T *Ref<T>::operator ->()
{
return m_ptr;
}
template <class T> Ref<T>::operator const T *() const
{
return m_ptr;
}
template <class T> Ref<T>::operator T *()
{
return m_ptr;
}
#endif // __REF_H__