Files
LNXRNT/Kinc/Backends/Graphics4/Direct3D9/Sources/kinc/backend/graphics4/Direct3D9.cpp
2025-01-29 10:55:49 +01:00

842 lines
26 KiB
C++

#include <kinc/display.h>
#include <kinc/graphics4/graphics.h>
#include <kinc/graphics4/indexbuffer.h>
#include <kinc/graphics4/pipeline.h>
#include <kinc/graphics4/shader.h>
#include <kinc/graphics4/texture.h>
#include <kinc/graphics4/vertexbuffer.h>
#include <kinc/math/core.h>
#undef CreateWindow
#include <kinc/system.h>
#include <kinc/window.h>
#include <kinc/backend/SystemMicrosoft.h>
#include <kinc/backend/Windows.h>
#include <kinc/log.h>
#include <vector>
#include "Direct3D9.h"
LPDIRECT3D9 d3d;
LPDIRECT3DDEVICE9 device;
namespace {
HWND hWnd;
int _width;
int _height;
unsigned hz;
bool vsync;
bool resizable;
D3DVIEWPORT9 vp;
bool swapBuffers() {
HRESULT result;
if (resizable) {
RECT vRect;
GetClientRect(hWnd, &vRect);
result = device->Present(&vRect, &vRect, 0, 0);
}
else {
result = device->Present(0, 0, 0, 0);
}
return result != D3DERR_DEVICELOST;
}
kinc_g4_shader_t *pixelShader = nullptr;
kinc_g4_shader_t *vertexShader = nullptr;
IDirect3DSurface9 *backBuffer = nullptr;
IDirect3DSurface9 *depthBuffer = nullptr;
void initDeviceStates() {
D3DCAPS9 caps;
device->GetDeviceCaps(&caps);
device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
// device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
#ifndef USE_SHADER
device->SetRenderState(D3DRS_LIGHTING, FALSE);
#endif
device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
#ifndef USE_SHADER
device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_CURRENT);
kinc_microsoft_affirm(device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE));
kinc_microsoft_affirm(device->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE));
#endif
// if (d3dpp.Windowed != TRUE) Cursor->Hide();
device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
for (int i = 0; i < 16; ++i) {
device->SetSamplerState(i, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC);
device->SetSamplerState(i, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC);
device->SetSamplerState(i, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
device->SetSamplerState(i, D3DSAMP_MAXANISOTROPY, caps.MaxAnisotropy);
}
device->SetSamplerState(D3DVERTEXTEXTURESAMPLER0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
device->SetSamplerState(D3DVERTEXTEXTURESAMPLER0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC);
device->SetRenderState(D3DRS_ZENABLE, FALSE);
device->Clear(0, 0, D3DCLEAR_TARGET, 0, 0, 0);
}
}
void kinc_g4_internal_destroy_window(int window) {}
void kinc_g4_internal_destroy() {}
extern "C" void kinc_internal_resize(int width, int height) {
if (!resizable) {
return;
}
_width = width;
_height = height;
kinc_g4_viewport(0, 0, width, height);
/*D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = (!fullscreen) ? TRUE : FALSE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferCount = 2;
d3dpp.BackBufferWidth = width;
d3dpp.BackBufferHeight = height;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24X8;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; //D3DPRESENT_INTERVAL_IMMEDIATE;
if (antialiasing()) {
if (SUCCEEDED(d3d->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_A8R8G8B8, FALSE, D3DMULTISAMPLE_4_SAMPLES, nullptr)))
d3dpp.MultiSampleType = D3DMULTISAMPLE_4_SAMPLES;
if (SUCCEEDED(d3d->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_A8R8G8B8, FALSE, D3DMULTISAMPLE_8_SAMPLES, nullptr)))
d3dpp.MultiSampleType = D3DMULTISAMPLE_8_SAMPLES;
}
else {
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
}
device->Reset(&d3dpp);
initDeviceStates();*/
}
extern "C" void kinc_internal_change_framebuffer(int window, struct kinc_framebuffer_options *frame) {}
void kinc_g4_internal_init() {}
void kinc_g4_internal_init_window(int windowId, int depthBufferBits, int stencilBufferBits, bool vsync) {
bool fullscreen = kinc_window_get_mode(windowId) == KINC_WINDOW_MODE_FULLSCREEN || kinc_window_get_mode(windowId) == KINC_WINDOW_MODE_EXCLUSIVE_FULLSCREEN;
d3d = Direct3DCreate9(D3D_SDK_VERSION);
hWnd = kinc_windows_window_handle(windowId);
long style = GetWindowLong(hWnd, GWL_STYLE);
resizable = false;
if ((style & WS_SIZEBOX) != 0) {
resizable = true;
}
if ((style & WS_MAXIMIZEBOX) != 0) {
resizable = true;
}
// TODO (DK) just setup the primary window for now and ignore secondaries
// -this should probably be implemented via swap chain for real at a later time
// -http://www.mvps.org/directx/articles/rendering_to_multiple_windows.htm
if (windowId > 0) {
return;
}
#ifdef KORE_WINDOWS
// TODO (DK) convert depthBufferBits + stencilBufferBits to: d3dpp.AutoDepthStencilFormat = D3DFMT_D24X8;
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = (!fullscreen) ? TRUE : FALSE;
if (resizable) {
d3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
d3dpp.BackBufferCount = 1;
kinc_display_mode_t mode = kinc_display_current_mode(kinc_primary_display());
d3dpp.BackBufferWidth = mode.width;
d3dpp.BackBufferHeight = mode.height;
}
else {
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferCount = 2;
d3dpp.BackBufferWidth = kinc_window_width(windowId);
d3dpp.BackBufferHeight = kinc_window_height(windowId);
}
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24X8;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
// d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
if (kinc_g4_antialiasing_samples() > 1) {
for (int samples = min(kinc_g4_antialiasing_samples(), 16); samples > 1; --samples) {
if (SUCCEEDED(d3d->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_A8R8G8B8, FALSE, (D3DMULTISAMPLE_TYPE)samples, nullptr))) {
d3dpp.MultiSampleType = (D3DMULTISAMPLE_TYPE)samples;
break;
}
}
}
#endif
if (!SUCCEEDED(d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &device)))
d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &device);
// d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &device);
#ifdef KORE_WINDOWS
// if (System::hasShowWindowFlag(/*windowId*/)) {
ShowWindow(hWnd, SW_SHOWDEFAULT);
UpdateWindow(hWnd);
//}
#endif
initDeviceStates();
#ifdef KORE_WINDOWS
if (fullscreen) {
// hz = d3dpp.FullScreen_RefreshRateInHz;
D3DDISPLAYMODE mode;
device->GetDisplayMode(0, &mode);
hz = mode.RefreshRate;
}
if (!fullscreen || hz == 0) {
DEVMODE devMode;
EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &devMode);
hz = devMode.dmDisplayFrequency;
}
#endif
// vsync = d3dpp.PresentationInterval != D3DPRESENT_INTERVAL_IMMEDIATE;
kinc_ticks_t test1 = kinc_timestamp();
for (int i = 0; i < 3; ++i) {
kinc_g4_swap_buffers();
}
kinc_ticks_t test2 = kinc_timestamp();
if (test2 - test1 < (1.0 / hz) * kinc_frequency()) {
vsync = false;
}
else {
vsync = true;
}
_width = kinc_window_width(windowId);
_height = kinc_window_height(windowId);
}
void kinc_g4_flush() {}
namespace {
DWORD convertFilter(kinc_g4_texture_filter_t filter) {
switch (filter) {
case KINC_G4_TEXTURE_FILTER_POINT:
return D3DTEXF_POINT;
case KINC_G4_TEXTURE_FILTER_LINEAR:
return D3DTEXF_LINEAR;
case KINC_G4_TEXTURE_FILTER_ANISOTROPIC:
return D3DTEXF_ANISOTROPIC;
default:
return D3DTEXF_POINT;
}
}
DWORD convertMipFilter(kinc_g4_mipmap_filter_t filter) {
switch (filter) {
case KINC_G4_MIPMAP_FILTER_NONE:
return D3DTEXF_NONE;
case KINC_G4_MIPMAP_FILTER_POINT:
return D3DTEXF_POINT;
case KINC_G4_MIPMAP_FILTER_LINEAR:
return D3DTEXF_LINEAR;
default:
return D3DTEXF_NONE;
}
}
}
void kinc_g4_set_texture_magnification_filter(kinc_g4_texture_unit_t texunit, kinc_g4_texture_filter_t filter) {
device->SetSamplerState(texunit.stages[KINC_G4_SHADER_TYPE_FRAGMENT], D3DSAMP_MAGFILTER, convertFilter(filter));
}
void kinc_g4_set_texture3d_magnification_filter(kinc_g4_texture_unit_t texunit, kinc_g4_texture_filter_t filter) {
kinc_g4_set_texture_magnification_filter(texunit, filter);
}
void kinc_g4_set_texture_minification_filter(kinc_g4_texture_unit_t texunit, kinc_g4_texture_filter_t filter) {
device->SetSamplerState(texunit.stages[KINC_G4_SHADER_TYPE_FRAGMENT], D3DSAMP_MINFILTER, convertFilter(filter));
}
void kinc_g4_set_texture3d_minification_filter(kinc_g4_texture_unit_t texunit, kinc_g4_texture_filter_t filter) {
kinc_g4_set_texture_minification_filter(texunit, filter);
}
void kinc_g4_set_texture_mipmap_filter(kinc_g4_texture_unit_t texunit, kinc_g4_mipmap_filter_t filter) {
device->SetSamplerState(texunit.stages[KINC_G4_SHADER_TYPE_FRAGMENT], D3DSAMP_MIPFILTER, convertMipFilter(filter));
}
void kinc_g4_set_texture3d_mipmap_filter(kinc_g4_texture_unit_t texunit, kinc_g4_mipmap_filter_t filter) {
kinc_g4_set_texture_mipmap_filter(texunit, filter);
}
void kinc_g4_set_texture_compare_mode(kinc_g4_texture_unit_t unit, bool enabled) {}
void kinc_g4_set_texture_compare_func(kinc_g4_texture_unit_t unit, kinc_g4_compare_mode_t mode) {}
void kinc_g4_set_cubemap_compare_mode(kinc_g4_texture_unit_t unit, bool enabled) {}
void kinc_g4_set_cubemap_compare_func(kinc_g4_texture_unit_t unit, kinc_g4_compare_mode_t mode) {}
void kinc_g4_set_texture_max_anisotropy(kinc_g4_texture_unit_t unit, uint16_t max_anisotropy) {
device->SetSamplerState(unit.stages[KINC_G4_SHADER_TYPE_FRAGMENT], D3DSAMP_MAXANISOTROPY, max_anisotropy);
}
void kinc_g4_set_cubemap_max_anisotropy(kinc_g4_texture_unit_t unit, uint16_t max_anisotropy) {}
void kinc_g4_set_texture_lod(kinc_g4_texture_unit_t unit, float lod_min_clamp, float lod_max_clamp) {
// device->SetSamplerState(unit.impl.unit, D3DSAMP_, );
}
void kinc_g4_set_cubemap_lod(kinc_g4_texture_unit_t unit, float lod_min_clamp, float lod_max_clamp) {}
void kinc_g4_set_render_targets(struct kinc_g4_render_target **targets, int count) {
// if (backBuffer != nullptr) backBuffer->Release();
if (backBuffer == nullptr) {
device->GetRenderTarget(0, &backBuffer);
device->GetDepthStencilSurface(&depthBuffer);
}
kinc_microsoft_affirm(device->SetDepthStencilSurface(targets[0]->impl.depthSurface));
for (int i = 0; i < count; ++i) {
kinc_microsoft_affirm(device->SetRenderTarget(i, targets[i]->impl.colorSurface));
}
}
void kinc_g4_set_render_target_face(struct kinc_g4_render_target *texture, int face) {}
int kinc_g4_max_bound_textures(void) {
return 8;
}
// void Graphics::setDepthStencilTarget(Texture* texture) {
// //if (depthBuffer != nullptr) depthBuffer->Release();
// device->GetDepthStencilSurface(&depthBuffer);
// Microsoft::affirm(device->SetDepthStencilSurface(dcast<D3D9Texture*>(texture)->getSurface()));
//}
void kinc_g4_restore_render_target() {
if (backBuffer != nullptr) {
device->SetRenderTarget(0, backBuffer);
device->SetRenderTarget(1, nullptr);
backBuffer->Release();
backBuffer = nullptr;
device->SetDepthStencilSurface(depthBuffer);
depthBuffer->Release();
depthBuffer = nullptr;
kinc_g4_viewport(0, 0, _width, _height);
}
}
void kinc_g4_draw_indexed_vertices() {
device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, kinc_g4_vertex_buffer_count(kinc_internal_current_vertex_buffer), 0,
kinc_g4_index_buffer_count(kinc_internal_current_index_buffer) / 3);
}
void kinc_g4_draw_indexed_vertices_from_to(int start, int count) {
device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, kinc_g4_vertex_buffer_count(kinc_internal_current_vertex_buffer), start, count / 3);
}
void kinc_g4_draw_indexed_vertices_from_to_from(int start, int count, int vertex_offset) {
device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, vertex_offset, 0, kinc_g4_vertex_buffer_count(kinc_internal_current_vertex_buffer), start, count / 3);
}
void kinc_g4_draw_indexed_vertices_instanced(int instanceCount) {
kinc_microsoft_affirm(device->SetStreamSourceFreq(kinc_internal_current_vertex_buffer->impl._offset, (D3DSTREAMSOURCE_INDEXEDDATA | instanceCount)));
device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, kinc_g4_vertex_buffer_count(kinc_internal_current_vertex_buffer), 0,
kinc_g4_index_buffer_count(kinc_internal_current_index_buffer) / 3);
}
void kinc_g4_draw_indexed_vertices_instanced_from_to(int instanceCount, int start, int count) {
kinc_microsoft_affirm(device->SetStreamSourceFreq(kinc_internal_current_vertex_buffer->impl._offset, (D3DSTREAMSOURCE_INDEXEDDATA | instanceCount)));
device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, kinc_g4_vertex_buffer_count(kinc_internal_current_vertex_buffer), start, count / 3);
}
void kinc_g4_set_texture_addressing(kinc_g4_texture_unit_t unit, kinc_g4_texture_direction_t dir, kinc_g4_texture_addressing_t addressing) {
DWORD value = 0;
switch (addressing) {
case KINC_G4_TEXTURE_ADDRESSING_REPEAT:
value = D3DTADDRESS_WRAP;
break;
case KINC_G4_TEXTURE_ADDRESSING_MIRROR:
value = D3DTADDRESS_MIRROR;
break;
case KINC_G4_TEXTURE_ADDRESSING_CLAMP:
value = D3DTADDRESS_CLAMP;
break;
case KINC_G4_TEXTURE_ADDRESSING_BORDER:
value = D3DTADDRESS_BORDER;
break;
}
device->SetSamplerState(unit.stages[KINC_G4_SHADER_TYPE_FRAGMENT], dir == KINC_G4_TEXTURE_DIRECTION_U ? D3DSAMP_ADDRESSU : D3DSAMP_ADDRESSV, value);
}
void kinc_g4_set_texture3d_addressing(kinc_g4_texture_unit_t unit, kinc_g4_texture_direction_t dir, kinc_g4_texture_addressing_t addressing) {
kinc_g4_set_texture_addressing(unit, dir, addressing);
}
namespace {
void tod3dmatrix(kinc_matrix4x4_t *matrix, D3DMATRIX &d3dm) {
d3dm._11 = kinc_matrix4x4_get(matrix, 0, 0);
d3dm._12 = kinc_matrix4x4_get(matrix, 0, 1);
d3dm._13 = kinc_matrix4x4_get(matrix, 0, 2);
d3dm._14 = kinc_matrix4x4_get(matrix, 0, 3);
d3dm._21 = kinc_matrix4x4_get(matrix, 1, 0);
d3dm._22 = kinc_matrix4x4_get(matrix, 1, 1);
d3dm._23 = kinc_matrix4x4_get(matrix, 1, 2);
d3dm._24 = kinc_matrix4x4_get(matrix, 1, 3);
d3dm._31 = kinc_matrix4x4_get(matrix, 2, 0);
d3dm._32 = kinc_matrix4x4_get(matrix, 2, 1);
d3dm._33 = kinc_matrix4x4_get(matrix, 2, 2);
d3dm._34 = kinc_matrix4x4_get(matrix, 2, 3);
d3dm._41 = kinc_matrix4x4_get(matrix, 3, 0);
d3dm._42 = kinc_matrix4x4_get(matrix, 3, 1);
d3dm._43 = kinc_matrix4x4_get(matrix, 3, 2);
d3dm._44 = kinc_matrix4x4_get(matrix, 3, 3);
}
}
void kinc_g4_clear(unsigned flags, unsigned color, float depth, int stencil) {
device->Clear(0, nullptr, flags, color, depth, stencil);
}
void kinc_g4_begin(int window) {
// TODO (DK) ignore secondary windows for now
if (window > 0) {
return;
}
kinc_g4_viewport(0, 0, _width, _height);
device->BeginScene();
}
void kinc_g4_viewport(int x, int y, int width, int height) {
vp.X = x;
vp.Y = y;
vp.Width = width;
vp.Height = height;
device->SetViewport(&vp);
}
void kinc_g4_scissor(int x, int y, int width, int height) {
device->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
RECT rc;
rc.left = x;
rc.top = y;
rc.right = x + width;
rc.bottom = y + height;
device->SetScissorRect(&rc);
}
void kinc_g4_disable_scissor() {
device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
}
void kinc_g4_end(int window) {
// TODO (DK) ignore secondary windows for now
if (window > 0) {
return;
}
/*if (backBuffer != nullptr) {
backBuffer->Release();
backBuffer = nullptr;
}*/
device->EndScene();
}
bool kinc_window_vsynced(int window) {
return vsync;
}
// unsigned Graphics4::refreshRate() {
// return hz;
//}
bool kinc_g4_swap_buffers() {
return ::swapBuffers();
}
void kinc_g4_set_stencil_reference_value(int value) {}
void kinc_g4_set_blend_constant(float r, float g, float b, float a) {
device->SetRenderState(D3DRS_BLENDFACTOR, D3DCOLOR_RGBA((int)(r * 255), (int)(g * 255), (int)(b * 255), (int)(a * 255)));
}
void kinc_g4_set_bool(kinc_g4_constant_location_t position, bool value) {
if (position.impl.shaderType == -1)
return;
BOOL bools[4];
bools[0] = value ? 1 : 0;
bools[1] = bools[0];
bools[2] = bools[0];
bools[3] = bools[0];
if (position.impl.shaderType == 0)
device->SetVertexShaderConstantB(position.impl.reg.regindex, &bools[0], 1);
else
device->SetPixelShaderConstantB(position.impl.reg.regindex, &bools[0], 1);
}
void kinc_g4_set_int(kinc_g4_constant_location_t position, int value) {
if (position.impl.shaderType == -1)
return;
if (position.impl.reg.regtype == 'f') {
kinc_g4_set_float(position, (float)value);
}
else {
int ints[4];
ints[0] = value;
ints[1] = value;
ints[2] = value;
ints[3] = value;
if (position.impl.shaderType == 0)
device->SetVertexShaderConstantI(position.impl.reg.regindex, &ints[0], 1);
else
device->SetPixelShaderConstantI(position.impl.reg.regindex, &ints[0], 1);
}
}
void kinc_g4_set_int2(kinc_g4_constant_location_t position, int value1, int value2) {
if (position.impl.shaderType == -1)
return;
if (position.impl.reg.regtype == 'f') {
kinc_g4_set_float2(position, (float)value1, (float)value2);
}
else {
int ints[4];
ints[0] = value1;
ints[1] = value2;
ints[2] = value1;
ints[3] = value2;
if (position.impl.shaderType == 0)
device->SetVertexShaderConstantI(position.impl.reg.regindex, &ints[0], 1);
else
device->SetPixelShaderConstantI(position.impl.reg.regindex, &ints[0], 1);
}
}
void kinc_g4_set_int3(kinc_g4_constant_location_t position, int value1, int value2, int value3) {
if (position.impl.shaderType == -1)
return;
if (position.impl.reg.regtype == 'f') {
kinc_g4_set_float3(position, (float)value1, (float)value2, (float)value3);
}
else {
int ints[4];
ints[0] = value1;
ints[1] = value2;
ints[2] = value3;
ints[3] = value1;
if (position.impl.shaderType == 0)
device->SetVertexShaderConstantI(position.impl.reg.regindex, &ints[0], 1);
else
device->SetPixelShaderConstantI(position.impl.reg.regindex, &ints[0], 1);
}
}
void kinc_g4_set_int4(kinc_g4_constant_location_t position, int value1, int value2, int value3, int value4) {
if (position.impl.shaderType == -1)
return;
if (position.impl.reg.regtype == 'f') {
kinc_g4_set_float4(position, (float)value1, (float)value2, (float)value3, (float)value4);
}
else {
int ints[4];
ints[0] = value1;
ints[1] = value2;
ints[2] = value3;
ints[3] = value4;
if (position.impl.shaderType == 0)
device->SetVertexShaderConstantI(position.impl.reg.regindex, &ints[0], 1);
else
device->SetPixelShaderConstantI(position.impl.reg.regindex, &ints[0], 1);
}
}
void kinc_g4_set_ints(kinc_g4_constant_location_t location, int *values, int count) {
if (location.impl.shaderType == -1)
return;
int registerCount = (count + 3) / 4; // round up
if (registerCount == count / 4) { // round down
if (location.impl.shaderType == 0)
device->SetVertexShaderConstantI(location.impl.reg.regindex, values, registerCount);
else
device->SetPixelShaderConstantI(location.impl.reg.regindex, values, registerCount);
}
else {
int *data = (int *)alloca(registerCount * 4 * sizeof(int));
memcpy(data, values, count * sizeof(int));
if (location.impl.shaderType == 0)
device->SetVertexShaderConstantI(location.impl.reg.regindex, data, registerCount);
else
device->SetPixelShaderConstantI(location.impl.reg.regindex, data, registerCount);
}
}
void kinc_g4_set_float(kinc_g4_constant_location_t position, float value) {
if (position.impl.shaderType == -1)
return;
float floats[4];
floats[0] = value;
floats[1] = value;
floats[2] = value;
floats[3] = value;
if (position.impl.shaderType == 0)
device->SetVertexShaderConstantF(position.impl.reg.regindex, floats, 1);
else
device->SetPixelShaderConstantF(position.impl.reg.regindex, floats, 1);
}
void kinc_g4_set_float2(kinc_g4_constant_location_t position, float value1, float value2) {
if (position.impl.shaderType == -1)
return;
float floats[4];
floats[0] = value1;
floats[1] = value2;
floats[2] = value1;
floats[3] = value2;
if (position.impl.shaderType == 0)
device->SetVertexShaderConstantF(position.impl.reg.regindex, floats, 1);
else
device->SetPixelShaderConstantF(position.impl.reg.regindex, floats, 1);
}
void kinc_g4_set_float3(kinc_g4_constant_location_t position, float value1, float value2, float value3) {
if (position.impl.shaderType == -1)
return;
float floats[4];
floats[0] = value1;
floats[1] = value2;
floats[2] = value3;
floats[3] = value1;
if (position.impl.shaderType == 0)
device->SetVertexShaderConstantF(position.impl.reg.regindex, floats, 1);
else
device->SetPixelShaderConstantF(position.impl.reg.regindex, floats, 1);
}
void kinc_g4_set_float4(kinc_g4_constant_location_t position, float value1, float value2, float value3, float value4) {
if (position.impl.shaderType == -1)
return;
float floats[4];
floats[0] = value1;
floats[1] = value2;
floats[2] = value3;
floats[3] = value4;
if (position.impl.shaderType == 0)
device->SetVertexShaderConstantF(position.impl.reg.regindex, floats, 1);
else
device->SetPixelShaderConstantF(position.impl.reg.regindex, floats, 1);
}
void kinc_g4_set_floats(kinc_g4_constant_location_t location, float *values, int count) {
if (location.impl.shaderType == -1)
return;
int registerCount = (count + 3) / 4; // round up
if (registerCount == count / 4) { // round down
if (location.impl.shaderType == 0)
device->SetVertexShaderConstantF(location.impl.reg.regindex, values, registerCount);
else
device->SetPixelShaderConstantF(location.impl.reg.regindex, values, registerCount);
}
else {
float *data = (float *)alloca(registerCount * 4 * sizeof(float));
memcpy(data, values, count * sizeof(float));
if (location.impl.shaderType == 0)
device->SetVertexShaderConstantF(location.impl.reg.regindex, data, registerCount);
else
device->SetPixelShaderConstantF(location.impl.reg.regindex, data, registerCount);
}
}
void kinc_g4_set_matrix4(kinc_g4_constant_location_t location, kinc_matrix4x4_t *value) {
if (location.impl.shaderType == -1)
return;
float floats[16];
for (int y = 0; y < 4; ++y) {
for (int x = 0; x < 4; ++x) {
floats[y * 4 + x] = kinc_matrix4x4_get(value, y, x);
}
}
if (location.impl.shaderType == 0)
device->SetVertexShaderConstantF(location.impl.reg.regindex, floats, 4);
else
device->SetPixelShaderConstantF(location.impl.reg.regindex, floats, 4);
}
void kinc_g4_set_matrix3(kinc_g4_constant_location_t location, kinc_matrix3x3_t *value) {
if (location.impl.shaderType == -1)
return;
float floats[12];
for (int y = 0; y < 3; ++y) {
for (int x = 0; x < 3; ++x) {
floats[y * 4 + x] = kinc_matrix3x3_get(value, y, x);
}
}
if (location.impl.shaderType == 0)
device->SetVertexShaderConstantF(location.impl.reg.regindex, floats, 3);
else
device->SetPixelShaderConstantF(location.impl.reg.regindex, floats, 3);
}
void kinc_g4_set_vertex_buffers(kinc_g4_vertex_buffer_t **buffers, int count) {
for (int i = 0; i < count; ++i) {
kinc_internal_g4_vertex_buffer_set(buffers[i], i);
}
}
void kinc_g4_set_index_buffer(kinc_g4_index_buffer_t *buffer) {
kinc_internal_g4_index_buffer_set(buffer);
}
#ifdef KINC_KONG
void kinc_internal_texture_set(kinc_g4_texture_t *texture, uint32_t unit);
void kinc_g4_set_texture(uint32_t unit, struct kinc_g4_texture *texture) {
kinc_internal_texture_set(texture, unit);
}
#else
void kinc_internal_texture_set(kinc_g4_texture_t *texture, kinc_g4_texture_unit_t unit);
void kinc_g4_set_texture(kinc_g4_texture_unit_t unit, struct kinc_g4_texture *texture) {
kinc_internal_texture_set(texture, unit);
}
#endif
void kinc_g4_set_image_texture(kinc_g4_texture_unit_t unit, struct kinc_g4_texture *texture) {}
unsigned queryCount = 0;
std::vector<IDirect3DQuery9 *> queryPool;
bool kinc_g4_init_occlusion_query(unsigned *occlusionQuery) {
// check if the runtime supports queries
HRESULT result = device->CreateQuery(D3DQUERYTYPE_OCCLUSION, NULL);
if (FAILED(result)) {
kinc_log(KINC_LOG_LEVEL_WARNING, "Internal query creation failed, result: 0x%X.", result);
return false;
}
IDirect3DQuery9 *pQuery = nullptr;
device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &pQuery);
queryPool.push_back(pQuery);
*occlusionQuery = queryCount;
++queryCount;
return true;
}
void kinc_g4_delete_occlusion_query(unsigned occlusionQuery) {
if (occlusionQuery < queryPool.size())
queryPool[occlusionQuery] = nullptr;
}
void kinc_g4_start_occlusion_query(unsigned occlusionQuery) {
IDirect3DQuery9 *pQuery = queryPool[occlusionQuery];
if (pQuery != nullptr) {
pQuery->Issue(D3DISSUE_BEGIN);
}
}
void kinc_g4_end_occlusion_query(unsigned occlusionQuery) {
IDirect3DQuery9 *pQuery = queryPool[occlusionQuery];
if (pQuery != nullptr) {
pQuery->Issue(D3DISSUE_END);
}
}
bool kinc_g4_are_query_results_available(unsigned occlusionQuery) {
IDirect3DQuery9 *pQuery = queryPool[occlusionQuery];
if (pQuery != nullptr) {
if (S_OK == pQuery->GetData(0, 0, 0)) {
return true;
}
}
return false;
}
void kinc_g4_get_query_results(unsigned occlusionQuery, unsigned *pixelCount) {
IDirect3DQuery9 *pQuery = queryPool[occlusionQuery];
if (pQuery != nullptr) {
DWORD numberOfPixelsDrawn;
HRESULT result = pQuery->GetData(&numberOfPixelsDrawn, sizeof(DWORD), 0);
if (S_OK == result) {
*pixelCount = numberOfPixelsDrawn;
}
else {
kinc_log(KINC_LOG_LEVEL_WARNING, "Check first if results are available");
*pixelCount = 0;
}
}
}
void kinc_g4_set_texture_array(kinc_g4_texture_unit_t unit, struct kinc_g4_texture_array *array) {}
void kinc_g4_set_pipeline(struct kinc_g4_pipeline *pipeline) {
kinc_g4_internal_set_pipeline(pipeline);
}
bool kinc_g4_supports_instanced_rendering() {
return true;
}
bool kinc_g4_supports_compute_shaders() {
return false;
}
bool kinc_g4_supports_blend_constants() {
D3DCAPS9 pCaps = {};
if (FAILED(device->GetDeviceCaps(&pCaps))) {
kinc_log(KINC_LOG_LEVEL_ERROR, "Failed to get device caps");
return false;
}
return ((pCaps.SrcBlendCaps & D3DPBLENDCAPS_BLENDFACTOR) != 0) && ((pCaps.DestBlendCaps & D3DPBLENDCAPS_BLENDFACTOR) != 0);
}
bool kinc_g4_supports_non_pow2_textures() {
D3DCAPS9 pCaps = {};
if (FAILED(device->GetDeviceCaps(&pCaps))) {
kinc_log(KINC_LOG_LEVEL_ERROR, "Failed to get device caps");
return false;
}
// only advertise full npot support
return ((pCaps.TextureCaps & D3DPTEXTURECAPS_POW2) == 0) && ((pCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) == 0);
}
bool kinc_g4_render_targets_inverted_y(void) {
return false;
}
void kinc_g4_set_constant_buffer(uint32_t id, struct kinc_g4_constant_buffer *buffer) {}