From 6b94d7d0e0ad262dab541253ba30a67bc16a24db Mon Sep 17 00:00:00 2001 From: XProger Date: Fri, 11 May 2018 13:38:18 +0300 Subject: [PATCH] #15 basic D3D9 renderer (WIP) --- src/cache.h | 111 ++--- src/camera.h | 4 +- src/controller.h | 5 +- src/core.h | 84 +++- src/game.h | 6 +- src/gapi_d3d9.h | 533 ++++++++++++++++++++++ src/gapi_gl.h | 229 ++++++++-- src/gapi_gu.h | 8 +- src/inventory.h | 8 +- src/level.h | 22 +- src/mesh.h | 3 +- src/platform/win/OpenLara.vcxproj | 5 +- src/platform/win/OpenLara.vcxproj.filters | 1 + src/platform/win/main.cpp | 121 +++-- src/shader.h | 174 +------ src/shaders/base.hlsl | 81 ++++ src/shaders/compile_dx9.bat | 9 + src/shaders/filter.glsl | 8 - src/shaders/filter.hlsl | 81 ++++ src/shaders/gui.hlsl | 49 ++ src/shaders/shader.glsl | 28 +- src/shaders/water.glsl | 24 +- src/shaders/water.hlsl | 81 ++++ 23 files changed, 1292 insertions(+), 383 deletions(-) create mode 100644 src/gapi_d3d9.h create mode 100644 src/shaders/base.hlsl create mode 100644 src/shaders/compile_dx9.bat create mode 100644 src/shaders/filter.hlsl create mode 100644 src/shaders/gui.hlsl create mode 100644 src/shaders/water.hlsl diff --git a/src/cache.h b/src/cache.h index a639207..d34833f 100644 --- a/src/cache.h +++ b/src/cache.h @@ -8,10 +8,6 @@ #define NO_CLIP_PLANE 1000000.0f -#define WATER_FOG_DIST (6 * 1024) -//#define WATER_USE_GRID -#define UNDERWATER_COLOR "#define UNDERWATER_COLOR vec3(0.6, 0.9, 0.9)\n" - struct ShaderCache { enum Effect { FX_NONE = 0, FX_UNDERWATER = 1, FX_ALPHA_TEST = 2, FX_CLIP_PLANE = 4 }; @@ -97,7 +93,6 @@ struct ShaderCache { compile(Core::passFilter, Shader::FILTER_DOWNSAMPLE, fx, RS_COLOR_WRITE); compile(Core::passFilter, Shader::FILTER_GRAYSCALE, fx, RS_COLOR_WRITE); compile(Core::passFilter, Shader::FILTER_BLUR, fx, RS_COLOR_WRITE); - compile(Core::passFilter, Shader::FILTER_MIXER, fx, RS_COLOR_WRITE); } void prepareGUI(int fx) { @@ -114,92 +109,58 @@ struct ShaderCache { fx |= FX_ALPHA_TEST; #ifndef FFP - char def[1024], ext[255]; - ext[0] = 0; + int def[SD_MAX], defCount = 0; + + #define SD_ADD(x) (def[defCount++] = SD_##x) + if (Core::settings.detail.shadows) { if (Core::support.shadowSampler) { - #ifdef _GAPI_GLES - strcat(ext, "#extension GL_EXT_shadow_samplers : require\n"); - #endif - strcat(ext, "#define SHADOW_SAMPLER\n"); + SD_ADD(SHADOW_SAMPLER); } else { if (Core::support.depthTexture) - strcat(ext, "#define SHADOW_DEPTH\n"); + SD_ADD(SHADOW_DEPTH); else - strcat(ext, "#define SHADOW_COLOR\n"); + SD_ADD(SHADOW_COLOR); } } - const char *passNames[] = { "COMPOSE", "SHADOW", "AMBIENT", "WATER", "FILTER", "GUI" }; - const char *src = NULL; - const char *typ = NULL; switch (pass) { case Core::passCompose : case Core::passShadow : case Core::passAmbient : { - static const char *typeNames[] = { "SPRITE", "FLASH", "ROOM", "ENTITY", "MIRROR" }; + def[defCount++] = SD_TYPE_SPRITE + type; - src = GAPI::SHADER_BASE; - typ = typeNames[type]; - sprintf(def, "%s#define PASS_%s\n#define TYPE_%s\n#define MAX_LIGHTS %d\n#define MAX_CONTACTS %d\n#define WATER_FOG_DIST (1.0/%d.0)\n", ext, passNames[pass], typ, MAX_LIGHTS, MAX_CONTACTS, WATER_FOG_DIST); - #ifdef MERGE_SPRITES - if (type == Shader::SPRITE) - strcat(def, "#define ALIGN_SPRITES 1\n"); - #endif + if (fx & FX_UNDERWATER) SD_ADD(UNDERWATER); + if (fx & FX_ALPHA_TEST) SD_ADD(ALPHA_TEST); - if (fx & FX_UNDERWATER) strcat(def, "#define UNDERWATER\n" UNDERWATER_COLOR); - if (fx & FX_ALPHA_TEST) strcat(def, "#define ALPHA_TEST\n"); if (pass == Core::passCompose) { if (fx & FX_CLIP_PLANE) - strcat(def, "#define CLIP_PLANE\n"); - if (Core::settings.detail.lighting > Core::Settings::LOW && (type == Shader::ENTITY || type == Shader::ROOM)) - strcat(def, "#define OPT_LIGHTING\n"); + SD_ADD(CLIP_PLANE); if (Core::settings.detail.lighting > Core::Settings::MEDIUM && (type == Shader::ENTITY)) - strcat(def, "#define OPT_AMBIENT\n"); + SD_ADD(OPT_AMBIENT); if (Core::settings.detail.shadows > Core::Settings::LOW && (type == Shader::ENTITY || type == Shader::ROOM)) { - strcat(def, "#define OPT_SHADOW\n"); + SD_ADD(OPT_SHADOW); - if (Core::settings.detail.shadows > Core::Settings::MEDIUM) { - strcat(def, "#define OPT_SHADOW_HIGH\n"); - sprintf(def, "%s#define SHADOW_TEXEL vec3(1.0 / %d.0, 1.0 / %d.0, 0.0)\n#define SHADOW_OBJ_MAX %d\n", def, SHADOW_TEX_WIDTH, SHADOW_TEX_HEIGHT, SHADOW_OBJ_MAX); - } else - sprintf(def, "%s#define SHADOW_TEXEL vec3(1.0 / %d.0, 1.0 / %d.0, 0.0)\n#define SHADOW_OBJ_MAX %d\n", def, SHADOW_TEX_BIG_WIDTH, SHADOW_TEX_BIG_HEIGHT, 1); + if (Core::settings.detail.shadows > Core::Settings::MEDIUM) + SD_ADD(OPT_SHADOW_HIGH); } if (Core::settings.detail.shadows > Core::Settings::MEDIUM && (type == Shader::ROOM)) - strcat(def, "#define OPT_CONTACT\n"); + SD_ADD(OPT_CONTACT); if (Core::settings.detail.water > Core::Settings::MEDIUM && (type == Shader::ENTITY || type == Shader::ROOM) && (fx & FX_UNDERWATER)) - strcat(def, "#define OPT_CAUSTICS\n"); + SD_ADD(OPT_CAUSTICS); } break; } - case Core::passWater : { - static const char *typeNames[] = { "DROP", "STEP", "CAUSTICS", "MASK", "COMPOSE" }; - src = GAPI::SHADER_WATER; - typ = typeNames[type]; - sprintf(def, "%s#define PASS_%s\n#define WATER_%s\n#define WATER_FOG_DIST (1.0/%d.0)\n" UNDERWATER_COLOR, ext, passNames[pass], typ, WATER_FOG_DIST); - #ifdef WATER_USE_GRID - strcat(def, "#define WATER_USE_GRID\n"); - #endif - break; - } - case Core::passFilter : { - static const char *typeNames[] = { "DEFAULT", "DOWNSAMPLE", "GRAYSCALE", "BLUR", "MIXER", "EQUIRECTANGULAR" }; - src = GAPI::SHADER_FILTER; - typ = typeNames[type]; - sprintf(def, "%s#define PASS_%s\n#define FILTER_%s\n", ext, passNames[pass], typ); - break; - } - case Core::passGUI : { - static const char *typeNames[] = { "DEFAULT" }; - src = GAPI::SHADER_GUI; - typ = typeNames[type]; - sprintf(def, "%s#define PASS_%s\n", ext, passNames[pass]); - break; - } + case Core::passWater : def[defCount++] = SD_WATER_DROP + type; break; + case Core::passFilter : def[defCount++] = SD_FILTER_DEFAULT + type; break; + case Core::passGUI : break; default : ASSERT(false); } - LOG("shader: compile %s -> %s %s%s%s\n", passNames[pass], typ, (fx & FX_UNDERWATER) ? "underwater " : "", (fx & FX_ALPHA_TEST) ? "alphaTest " : "", (fx & FX_CLIP_PLANE) ? "clipPlane" : ""); - return shaders[pass][type][fx] = new Shader(src, def); + + #undef SD_ADD + + LOG("shader: %s(%d) %s%s%s\n", Core::passNames[pass], type, (fx & FX_UNDERWATER) ? "u" : "", (fx & FX_ALPHA_TEST) ? "a" : "", (fx & FX_CLIP_PLANE) ? "c" : ""); + return shaders[pass][type][fx] = new Shader(pass, def, defCount); #else return NULL; #endif @@ -220,7 +181,7 @@ struct ShaderCache { Shader *shader = getShader(pass, type, fx); if (shader) - shader->bind(); + shader->setup(); Core::setAlphaTest((fx & FX_ALPHA_TEST) != 0); } @@ -477,11 +438,11 @@ struct WaterCache { int *mf = new int[4 * w * 64 * h * 64]; memset(mf, 0, sizeof(int) * 4 * w * 64 * h * 64); - data[0] = new Texture(w * 64, h * 64, FMT_RGBA_HALF, 0, mf); - data[1] = new Texture(w * 64, h * 64, FMT_RGBA_HALF); + data[0] = new Texture(w * 64, h * 64, FMT_RGBA_HALF, OPT_TARGET, mf); + data[1] = new Texture(w * 64, h * 64, FMT_RGBA_HALF, OPT_TARGET); delete[] mf; - caustics = Core::settings.detail.water > Core::Settings::MEDIUM ? new Texture(512, 512, FMT_RGBA) : NULL; + caustics = Core::settings.detail.water > Core::Settings::MEDIUM ? new Texture(512, 512, FMT_RGBA, OPT_TARGET) : NULL; #ifdef BLUR_CAUSTICS caustics_tmp = Core::settings.detail.water > Core::Settings::MEDIUM ? new Texture(512, 512, Texture::RGBA) : NULL; #endif @@ -513,7 +474,7 @@ struct WaterCache { } drops[MAX_DROPS]; WaterCache(IGame *game) : game(game), level(game->getLevel()), refract(NULL), count(0), dropCount(0) { - reflect = new Texture(512, 512, FMT_RGBA); + reflect = new Texture(512, 512, FMT_RGBA, OPT_TARGET); } ~WaterCache() { @@ -628,7 +589,7 @@ struct WaterCache { game->setShader(Core::passWater, Shader::WATER_DROP); Core::active.shader->setParam(uTexParam, vec4(1.0f / item.data[0]->width, 1.0f / item.data[0]->height, 1.0f, 1.0f)); - vec3 rPosScale[2] = { vec3(0.0f), vec3(1.0f) }; + vec4 rPosScale[2] = { vec4(0.0f), vec4(1.0f) }; Core::active.shader->setParam(uPosScale, rPosScale[0], 2); for (int i = 0; i < dropCount; i++) { @@ -666,7 +627,7 @@ struct WaterCache { // calc caustics game->setShader(Core::passWater, Shader::WATER_CAUSTICS); - vec3 rPosScale[2] = { vec3(0.0f), vec3(32767.0f / PLANE_DETAIL) }; + vec4 rPosScale[2] = { vec4(0.0f), vec4(32767.0f / PLANE_DETAIL) }; Core::active.shader->setParam(uPosScale, rPosScale[0], 2); float sx = item.size.x * DETAIL / (item.data[0]->width / 2); @@ -713,7 +674,8 @@ struct WaterCache { Item &item = items[i]; if (!item.visible) continue; - Core::active.shader->setParam(uPosScale, item.pos, 2); + vec4 rPosScale[2] = { vec4(item.pos, 0.0f), vec4(item.size, 1.0) }; + Core::active.shader->setParam(uPosScale, rPosScale[0], 2); game->getMesh()->renderQuad(); } @@ -870,11 +832,12 @@ struct WaterCache { Core::setCullMode(cmNone); Core::setBlendMode(bmAlpha); #ifdef WATER_USE_GRID - vec3 rPosScale[2] = { item.pos, item.size * vec3(1.0f / PLANE_DETAIL, 512.0f, 1.0f / PLANE_DETAIL) }; + vec4 rPosScale[2] = { vec4(item.pos, 0.0f), vec4(item.size * vec3(1.0f / PLANE_DETAIL, 512.0f, 1.0f / PLANE_DETAIL), 1.0f) }; Core::active.shader->setParam(uPosScale, rPosScale[0], 2); game->getMesh()->renderPlane(); #else - Core::active.shader->setParam(uPosScale, item.pos, 2); + vec4 rPosScale[2] = { vec4(item.pos, 0.0f), vec4(item.size, 1.0) }; + Core::active.shader->setParam(uPosScale, rPosScale[0], 2); game->getMesh()->renderQuad(); #endif Core::setCullMode(cmFront); diff --git a/src/camera.h b/src/camera.h index b0a4410..860b372 100644 --- a/src/camera.h +++ b/src/camera.h @@ -514,9 +514,9 @@ struct Camera : ICamera { // update room for eye (with HMD offset) if (Core::settings.detail.stereo == Core::Settings::STEREO_VR) - level->getSector(eye.room, Core::viewPos); + level->getSector(eye.room, Core::viewPos.xyz()); - frustum->pos = Core::viewPos; + frustum->pos = Core::viewPos.xyz(); frustum->calcPlanes(Core::mViewProj); } diff --git a/src/controller.h b/src/controller.h index e7d1527..6298828 100644 --- a/src/controller.h +++ b/src/controller.h @@ -117,7 +117,7 @@ struct Controller { Basis *joints; int jointsFrame; - vec3 ambient[6]; + vec4 ambient[6]; float specular; float intensity; @@ -159,7 +159,7 @@ struct Controller { specular = 0.0f; intensity = e.intensity == -1 ? -1.0f : intensityf(e.intensity); timer = 0.0f; - ambient[0] = ambient[1] = ambient[2] = ambient[3] = ambient[4] = ambient[5] = vec3(intensityf(getRoom().ambient)); + ambient[0] = ambient[1] = ambient[2] = ambient[3] = ambient[4] = ambient[5] = vec4(intensityf(getRoom().ambient)); targetLight = NULL; updateLights(false); visibleMask = 0xFFFFFFFF; @@ -1255,7 +1255,6 @@ struct Controller { float alpha = lerp(0.7f, 0.90f, clamp((info.floor - boxA.max.y) / 1024.0f, 0.0f, 1.0f) ); float lum = 0.5f * (1.0f - alpha); Core::setMaterial(lum, lum, lum, alpha); - Core::active.shader->setParam(uAmbient, vec3(0.0f)); Core::setDepthWrite(false); mesh->renderShadowBlob(); diff --git a/src/core.h b/src/core.h index 4aa887f..67ddfbb 100644 --- a/src/core.h +++ b/src/core.h @@ -11,9 +11,10 @@ #define OS_PTHREAD_MT #ifdef WIN32 - #define _OS_WIN 1 - #define _GAPI_GL 1 - //#define _GAPI_VULKAN + #define _OS_WIN 1 + //#define _GAPI_GL 1 + #define _GAPI_D3D9 1 + //#define _GAPI_VULKAN 1 #include @@ -83,6 +84,7 @@ #include "utils.h" +// muse be equal with base shader #define SHADOW_OBJ_COLS 4 #define SHADOW_OBJ_ROWS 2 #define SHADOW_TEX_TILE 128 @@ -353,7 +355,8 @@ enum TexOption { OPT_CUBEMAP = 1, OPT_MIPMAPS = 2, OPT_NEAREST = 4, - OPT_PROXY = 8, + OPT_TARGET = 8, + OPT_PROXY = 16, }; // Pipeline State Object @@ -415,15 +418,50 @@ struct MeshRange { E( uViewPos ) \ E( uLightPos ) \ E( uLightColor ) \ - E( uAnimTexRanges ) \ - E( uAnimTexOffsets ) \ E( uRoomSize ) \ E( uPosScale ) \ E( uContacts ) -enum AttribType { SHADER_ATTRIBS(DECL_ENUM) aMAX }; -enum SamplerType { SHADER_SAMPLERS(DECL_ENUM) sMAX }; -enum UniformType { SHADER_UNIFORMS(DECL_ENUM) uMAX }; +#define SHADER_DEFINES(E) \ + /* shadow types */ \ + E( SHADOW_SAMPLER ) \ + E( SHADOW_DEPTH ) \ + E( SHADOW_COLOR ) \ + /* compose types */ \ + E( TYPE_SPRITE ) \ + E( TYPE_FLASH ) \ + E( TYPE_ROOM ) \ + E( TYPE_ENTITY ) \ + E( TYPE_MIRROR ) \ + /* water sub-passes */ \ + E( WATER_DROP ) \ + E( WATER_STEP ) \ + E( WATER_CAUSTICS ) \ + E( WATER_MASK ) \ + E( WATER_COMPOSE ) \ + /* filter types */ \ + E( FILTER_DEFAULT ) \ + E( FILTER_DOWNSAMPLE ) \ + E( FILTER_GRAYSCALE ) \ + E( FILTER_BLUR ) \ + E( FILTER_EQUIRECTANGULAR ) \ + /* options */ \ + E( UNDERWATER ) \ + E( ALPHA_TEST ) \ + E( CLIP_PLANE ) \ + E( OPT_AMBIENT ) \ + E( OPT_SHADOW ) \ + E( OPT_SHADOW_HIGH ) \ + E( OPT_CONTACT ) \ + E( OPT_CAUSTICS ) + +enum AttribType { SHADER_ATTRIBS(DECL_ENUM) aMAX }; +enum SamplerType { SHADER_SAMPLERS(DECL_ENUM) sMAX }; +enum UniformType { SHADER_UNIFORMS(DECL_ENUM) uMAX }; + +#define DECL_SD_ENUM(v) SD_##v, +enum ShaderDefine { SHADER_DEFINES(DECL_SD_ENUM) SD_MAX }; +#undef DECL_SD_ENUM const char *AttribName[aMAX] = { SHADER_ATTRIBS(DECL_STR) }; const char *SamplerName[sMAX] = { SHADER_SAMPLERS(DECL_STR) }; @@ -452,7 +490,7 @@ namespace Core { mat4 mModel, mView, mProj, mViewProj, mViewInv; mat4 mLightProj[SHADOW_OBJ_MAX]; Basis basis; - vec3 viewPos; + vec4 viewPos; vec4 lightPos[MAX_LIGHTS]; vec4 lightColor[MAX_LIGHTS]; vec4 params; @@ -463,17 +501,18 @@ namespace Core { enum Pass { passCompose, passShadow, passAmbient, passWater, passFilter, passGUI, passMAX } pass; + const char *passNames[Core::passMAX] = { "COMPOSE", "SHADOW", "AMBIENT", "WATER", "FILTER", "GUI" }; + Texture *defaultTarget; int32 renderState; struct Active { - const PSO *pso; - Shader *shader; - int32 renderState; - + const PSO *pso; + GAPI::Shader *shader; GAPI::Texture *textures[8]; GAPI::Texture *target; + int32 renderState; uint32 targetFace; uint32 targetOp; Viewport viewport; // TODO: ivec4 @@ -483,9 +522,6 @@ namespace Core { uint32 VAO; uint32 iBuffer; uint32 vBuffer; - #elif _GAPI_SCEGU - Index *iBuffer; - GAPI::Vertex *vBuffer; #endif int32 basisCount; @@ -527,6 +563,8 @@ namespace Core { #ifdef _GAPI_GL #include "gapi_gl.h" +#elif _GAPI_D3D9 + #include "gapi_d3d9.h" #elif _GAPI_GX #include "gapi_gx.h" #elif _GAPI_SCEGU @@ -890,9 +928,11 @@ namespace Core { void beginFrame() { Core::stats.start(); + GAPI::beginFrame(); } void endFrame() { + GAPI::endFrame(); Core::stats.stop(); } @@ -904,13 +944,15 @@ namespace Core { GAPI::setViewProj(mView, mProj); } - void DIP(int iStart, int iCount, Index *iBuffer) { + void DIP(GAPI::Mesh *mesh, const MeshRange &range) { + mesh->bind(range); + stats.dips++; - stats.tris += iCount / 3; + stats.tris += range.iCount / 3; validateRenderState(); - GAPI::DIP(iStart, iCount, iBuffer); + GAPI::DIP(mesh, range); } PSO* psoCreate(Shader *shader, uint32 renderState, TexFormat colorFormat = FMT_RGBA, TexFormat depthFormat = FMT_DEPTH, const vec4 &clearColor = vec4(0.0f)) { @@ -934,7 +976,7 @@ namespace Core { ASSERT(pso); ASSERT(pso->data); ASSERT(pso->shader); - ((Shader*)pso->shader)->bind(); + ((Shader*)pso->shader)->setup(); GAPI::bindPSO(pso); Core::active.pso = pso; diff --git a/src/game.h b/src/game.h index 3828ea7..a0bc1c8 100644 --- a/src/game.h +++ b/src/game.h @@ -72,7 +72,7 @@ namespace Game { } void init(const char *lvlName = NULL) { - #ifdef _DEBUG + #ifdef DEBUG_RENDER Debug::init(); #endif char fileName[255]; @@ -87,7 +87,7 @@ namespace Game { } void deinit() { - #ifdef _DEBUG + #ifdef DEBUG_RENDER Debug::deinit(); #endif delete level; @@ -183,7 +183,7 @@ namespace Game { PROFILE_TIMING(Core::stats.tFrame); level->render(); - #ifdef _DEBUG + #ifdef DEBUG_RENDER level->renderDebug(); #endif } diff --git a/src/gapi_d3d9.h b/src/gapi_d3d9.h new file mode 100644 index 0000000..1883de4 --- /dev/null +++ b/src/gapi_d3d9.h @@ -0,0 +1,533 @@ +#ifndef H_GAPI_D3D9 +#define H_GAPI_D3D9 + +#include "core.h" +#include + +#define PROFILE_MARKER(title) +#define PROFILE_LABEL(id, name, label) +#define PROFILE_TIMING(time) + +extern LPDIRECT3D9 D3D; +extern LPDIRECT3DDEVICE9 device; + +namespace GAPI { + #include "shaders/base_vs.h" + #include "shaders/base_ps.h" + #include "shaders/water_vs.h" + #include "shaders/water_ps.h" + #include "shaders/filter_vs.h" + #include "shaders/filter_ps.h" + #include "shaders/gui_vs.h" + #include "shaders/gui_ps.h" + + const char *SHADER_BASE = NULL; + const char *SHADER_WATER = NULL; + const char *SHADER_FILTER = NULL; + const char *SHADER_GUI = NULL; + + using namespace Core; + + typedef ::Vertex Vertex; + + int cullMode, blendMode; + uint32 clearColor; + + LPDIRECT3DVERTEXDECLARATION9 vertexDecl; + +// Shader + enum { + USAGE_VS, + USAGE_PS, + }; + + static const struct Binding { + int reg; + int usage; + } bindings[uMAX] = { + { 0, USAGE_VS | USAGE_PS }, // uParam + { 1, USAGE_VS | USAGE_PS }, // uTexParam + { 2, USAGE_VS | USAGE_PS }, // uViewProj + { 6, USAGE_VS | USAGE_PS }, // uBasis + { 70, USAGE_VS | USAGE_PS }, // uLightProj + { 102, USAGE_VS | USAGE_PS }, // uMaterial + { 103, USAGE_VS | USAGE_PS }, // uAmbient + { 109, USAGE_VS | USAGE_PS }, // uFogParams + { 110, USAGE_VS | USAGE_PS }, // uViewPos + { 111, USAGE_VS | USAGE_PS }, // uLightPos + { 115, USAGE_VS | USAGE_PS }, // uLightColor + { 119, USAGE_VS | USAGE_PS }, // uRoomSize + { 120, USAGE_VS | USAGE_PS }, // uPosScale + { 122, USAGE_VS | USAGE_PS }, // uContacts + }; + + struct Shader { + LPDIRECT3DVERTEXSHADER9 VS; + LPDIRECT3DPIXELSHADER9 PS; + + Shader() : VS(NULL), PS(NULL) {} + + void init(Core::Pass pass, int *def, int defCount) { + const BYTE *vSrc, *pSrc; + switch (pass) { + case Core::passCompose : + case Core::passShadow : + case Core::passAmbient : vSrc = BASE_VS; pSrc = BASE_PS; break; + case Core::passWater : vSrc = WATER_VS; pSrc = WATER_PS; break; + case Core::passFilter : vSrc = FILTER_VS; pSrc = FILTER_PS; break; + case Core::passGUI : vSrc = GUI_VS; pSrc = GUI_PS; break; + default : ASSERT(false); LOG("! wrong pass id\n"); return; + } + + device->CreateVertexShader ((DWORD*)vSrc, &VS); + device->CreatePixelShader ((DWORD*)pSrc, &PS); + } + + void deinit() { + if (VS) VS->Release(); + if (PS) PS->Release(); + } + + void bind() { + if (Core::active.shader != this) { + Core::active.shader = this; + device->SetVertexShader(VS); + device->SetPixelShader(PS); + } + } + + void setConstant(UniformType uType, const float *value, int vectors) { + const Binding &b = bindings[uType]; + if (b.usage | USAGE_VS) device->SetVertexShaderConstantF (b.reg, value, vectors); + if (b.usage | USAGE_PS) device->SetPixelShaderConstantF (b.reg, value, vectors); + } + + void setParam(UniformType uType, const vec4 &value, int count = 1) { + setConstant(uType, (float*)&value, count); + } + + void setParam(UniformType uType, const mat4 &value, int count = 1) { + setConstant(uType, (float*)&value, count * 4); + } + + void setParam(UniformType uType, const Basis &value, int count = 1) { + setConstant(uType, (float*)&value, count * 2); + } + }; + +// Texture + struct Texture { + LPDIRECT3DTEXTURE9 tex2D; + LPDIRECT3DCUBETEXTURE9 texCube; + + int width, height, origWidth, origHeight; + TexFormat fmt; + uint32 opt; + + Texture(int width, int height, uint32 opt) : tex2D(NULL), texCube(NULL), width(width), height(height), origWidth(width), origHeight(height), fmt(FMT_RGBA), opt(opt) {} + + void init(void *data) { + ASSERT((opt & OPT_PROXY) == 0); + + bool filter = (opt & OPT_NEAREST) == 0; + bool mipmaps = (opt & OPT_MIPMAPS) != 0; + bool cube = (opt & OPT_CUBEMAP) != 0; + bool isShadow = fmt == FMT_SHADOW; + + static const struct FormatDesc { + int bpp; + D3DFORMAT format; + } formats[FMT_MAX] = { + { 8, D3DFMT_L8 }, + { 32, D3DFMT_A8R8G8B8 }, + { 16, D3DFMT_R5G6B5 }, + { 16, D3DFMT_A1R5G5B5 }, + { 64, D3DFMT_A16B16G16R16 }, + { 64, D3DFMT_A16B16G16R16 }, + { 16, D3DFMT_D16 }, + { 32, D3DFMT_D24S8 }, + { 16, D3DFMT_D16 }, + }; + + FormatDesc desc = formats[fmt]; + + if (cube) { + device->CreateCubeTexture(width, 1, 0, desc.format, D3DPOOL_MANAGED, &texCube, NULL); + } else { + device->CreateTexture(width, height, 1, 0, desc.format, D3DPOOL_MANAGED, &tex2D, NULL); + if (data) { + D3DLOCKED_RECT rect; + tex2D->LockRect(0, &rect, NULL, 0); + memcpy(rect.pBits, data, width * height * (desc.bpp / 8)); + tex2D->UnlockRect(0); + } + } + } + + void deinit() { + if (tex2D) tex2D->Release(); + if (texCube) texCube->Release(); + } + + void generateMipMap() { + // TODO + } + + void bind(int sampler) { + if (opt & OPT_PROXY) return; + ASSERT(tex2D || texCube); + + if (Core::active.textures[sampler] != this) { + Core::active.textures[sampler] = this; + if (tex2D) + device->SetTexture(sampler, tex2D); + else if (texCube) + device->SetTexture(sampler, texCube); + } + } + + void unbind(int sampler) { + if (Core::active.textures[sampler]) { + Core::active.textures[sampler] = NULL; + device->SetTexture(sampler, NULL); + } + } + + void setFilterQuality(int value) { + bool filter = value > Core::Settings::LOW; + bool mipmaps = value > Core::Settings::MEDIUM; + + for (int i = 0; i < sMAX; i++) { + device->SetSamplerState(i, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); + device->SetSamplerState(i, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); + device->SetSamplerState(i, D3DSAMP_ADDRESSW, D3DTADDRESS_CLAMP); + device->SetSamplerState(i, D3DSAMP_MAGFILTER, filter ? D3DTEXF_LINEAR : D3DTEXF_POINT); + device->SetSamplerState(i, D3DSAMP_MINFILTER, filter ? D3DTEXF_LINEAR : D3DTEXF_POINT); + } + } + }; + +// Mesh + struct Mesh { + LPDIRECT3DINDEXBUFFER9 IB; + LPDIRECT3DVERTEXBUFFER9 VB; + + int iCount; + int vCount; + bool dynamic; + + Mesh(bool dynamic) : IB(NULL), VB(NULL), dynamic(dynamic) {} + + void init(Index *indices, int iCount, ::Vertex *vertices, int vCount, int aCount) { + this->iCount = iCount; + this->vCount = vCount; + + ASSERT(sizeof(GAPI::Vertex) == sizeof(::Vertex)); + + device->CreateIndexBuffer (iCount * sizeof(indices[0]), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &IB, NULL); + device->CreateVertexBuffer (vCount * sizeof(vertices[0]), D3DUSAGE_WRITEONLY, 0, D3DPOOL_MANAGED, &VB, NULL); + update(indices, iCount, vertices, vCount); + } + + void deinit() { + IB->Release(); + VB->Release(); + } + + void update(Index *indices, int iCount, ::Vertex *vertices, int vCount) { + ASSERT(sizeof(GAPI::Vertex) == sizeof(::Vertex)); + + void* ptr; + int size; + + if (indices && iCount) { + IB->Lock(0, size = iCount * sizeof(indices[0]), &ptr, 0); + memcpy(ptr, indices, size); + IB->Unlock(); + } + + if (vertices && vCount) { + VB->Lock(0, size = vCount * sizeof(vertices[0]), &ptr, 0); + memcpy(ptr, vertices, size); + VB->Unlock(); + } + } + + void bind(const MeshRange &range) const { + device->SetIndices(IB); + device->SetStreamSource(0, VB, 0, sizeof(Vertex)); + } + + void initNextRange(MeshRange &range, int &aIndex) const { + range.aIndex = -1; + } + }; + +// GLuint FBO, defaultFBO; + struct RenderTargetCache { + int count; + struct Item { +// GLuint ID; + int width; + int height; + } items[MAX_RENDER_BUFFERS]; + } rtCache[2]; + + void init() { + memset(rtCache, 0, sizeof(rtCache)); + + D3DADAPTER_IDENTIFIER9 adapterInfo; + D3D->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &adapterInfo); + LOG("Vendor : %s\n", adapterInfo.Description); + LOG("Renderer : Direct3D 9.0c\n"); + + support.maxAniso = 1; + support.maxVectors = 16; + support.shaderBinary = false; + support.VAO = false; + support.depthTexture = false; + support.shadowSampler = false; + support.discardFrame = false; + support.texNPOT = false; + support.texRG = false; + support.texBorder = false; + support.maxAniso = false; + support.colorFloat = false; + support.colorHalf = false; + support.texFloatLinear = false; + support.texFloat = false; + support.texHalfLinear = false; + support.texHalf = false; + + #ifdef PROFILE + support.profMarker = false; + support.profTiming = false; + #endif + + const D3DVERTEXELEMENT9 VERTEX_DECL[] = { + {0, 0, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, // aCoord + {0, 8, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0}, // aNormal + {0, 16, D3DDECLTYPE_SHORT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, // aTexCoord + {0, 24, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, // aColor + {0, 28, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1}, // aLight + D3DDECL_END() + }; + + device->CreateVertexDeclaration(VERTEX_DECL, &vertexDecl); +/* + if (support.maxAniso) + glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &support.maxAniso); + #ifdef _GAPI_GLES + glGetIntegerv(GL_MAX_VARYING_VECTORS, &support.maxVectors); + #else + support.maxVectors = 16; + #endif + glEnable(GL_SCISSOR_TEST); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&defaultFBO); + glGenFramebuffers(1, &FBO); +*/ + } + + void deinit() { + /* + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, &FBO); + + glBindRenderbuffer(GL_RENDERBUFFER, 0); + for (int b = 0; b < 2; b++) + for (int i = 0; i < rtCache[b].count; i++) + glDeleteRenderbuffers(1, &rtCache[b].items[i].ID); + */ + } + + void beginFrame() { + device->BeginScene(); + } + + void endFrame() { + device->EndScene(); + } + + void resetState() { + device->SetVertexDeclaration(vertexDecl); + device->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); + device->SetRenderState(D3DRS_LIGHTING, FALSE); + device->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); + } + + int cacheRenderTarget(bool depth, int width, int height) { + RenderTargetCache &cache = rtCache[depth]; + + for (int i = 0; i < cache.count; i++) + if (cache.items[i].width == width && cache.items[i].height == height) + return i; + + ASSERT(cache.count < MAX_RENDER_BUFFERS); + + RenderTargetCache::Item &item = cache.items[cache.count]; + item.width = width; + item.height = height; + /* + glGenRenderbuffers(1, &item.ID); + glBindRenderbuffer(GL_RENDERBUFFER, item.ID); + glRenderbufferStorage(GL_RENDERBUFFER, depth ? GL_RGB565 : GL_DEPTH_COMPONENT16, width, height); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + */ + return cache.count++; + } + + void bindTarget(Texture *target, int face) { + /* + if (!target) { // may be a null + glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO); + } else { + GLenum texTarget = GL_TEXTURE_2D; + if (target->opt & OPT_CUBEMAP) + texTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; + + bool depth = target->fmt == FMT_DEPTH || target->fmt == FMT_SHADOW; + + int rtIndex = cacheRenderTarget(depth, target->width, target->height); + + glBindFramebuffer(GL_FRAMEBUFFER, FBO); + glFramebufferTexture2D (GL_FRAMEBUFFER, depth ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0, texTarget, target->ID, 0); + glFramebufferRenderbuffer (GL_FRAMEBUFFER, depth ? GL_COLOR_ATTACHMENT0 : GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rtCache[depth].items[rtIndex].ID); + } + */ + } + + void discardTarget(bool color, bool depth) {} + + void copyTarget(Texture *dst, int xOffset, int yOffset, int x, int y, int width, int height) { + Core::active.textures[0] = NULL; + /* + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, dst->ID); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, x, y, width, height); + glBindTexture(GL_TEXTURE_2D, 0); + */ + } + + void setVSync(bool enable) { + // + } + + void waitVBlank() {} + + void clear(bool color, bool depth) { + uint32 flags = (color ? D3DCLEAR_TARGET : 0) | (depth ? D3DCLEAR_ZBUFFER : 0); + device->Clear(0, NULL, flags, clearColor, 1.0f, 0); + } + + void setClearColor(const vec4 &color) { + clearColor = (int(color.x * 255) << 16) | + (int(color.y * 255) << 8 ) | + (int(color.z * 255) ) | + (int(color.w * 255) << 24); + } + + void setViewport(const Viewport &vp) { + D3DVIEWPORT9 dv; + dv.X = vp.x; + dv.Y = vp.y; + dv.Width = vp.width; + dv.Height = vp.height; + dv.MinZ = 0.0f; + dv.MaxZ = 1.0f; + + RECT ds; + ds.left = vp.x; + ds.top = vp.y; + ds.right = vp.x + vp.width; + ds.bottom = vp.y + vp.height; + + device->SetViewport(&dv); + device->SetScissorRect(&ds); + } + + void setDepthTest(bool enable) { + device->SetRenderState(D3DRS_ZENABLE, enable); + } + + void setDepthWrite(bool enable) { + device->SetRenderState(D3DRS_ZWRITEENABLE, enable); + } + + void setColorWrite(bool r, bool g, bool b, bool a) { + device->SetRenderState(D3DRS_COLORWRITEENABLE, + (r ? D3DCOLORWRITEENABLE_RED : 0) | + (g ? D3DCOLORWRITEENABLE_GREEN : 0) | + (b ? D3DCOLORWRITEENABLE_BLUE : 0) | + (a ? D3DCOLORWRITEENABLE_ALPHA : 0)); + } + + void setAlphaTest(bool enable) {} + + void setCullMode(int rsMask) { + cullMode = rsMask; + switch (rsMask) { + case RS_CULL_BACK : device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW); break; + case RS_CULL_FRONT : device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW); break; + default : device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + } + } + + void setBlendMode(int rsMask) { + blendMode = rsMask; + switch (rsMask) { + case RS_BLEND_ALPHA : + device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + break; + case RS_BLEND_ADD : + device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); + device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); + break; + case RS_BLEND_MULT : + device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_DESTCOLOR); + device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ZERO); + break; + case RS_BLEND_PREMULT : + device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); + device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + break; + default : + device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + return; + } + device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + } + + void setViewProj(const mat4 &mView, const mat4 &mProj) { + } + + void DIP(Mesh *mesh, const MeshRange &range) { + device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, range.vStart, 0, mesh->vCount, range.iStart, range.iCount / 3); + } + + vec4 copyPixel(int x, int y) { + ubyte4 c; +// glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &c); + return vec4(float(c.x), float(c.y), float(c.z), float(c.w)) * (1.0f / 255.0f); + } + + void initPSO(PSO *pso) { + ASSERT(pso); + ASSERT(pso && pso->data == NULL); + pso->data = &pso; + } + + void deinitPSO(PSO *pso) { + ASSERT(pso); + ASSERT(pso->data != NULL); + pso->data = NULL; + } + + void bindPSO(const PSO *pso) { + // + } +} + +#endif \ No newline at end of file diff --git a/src/gapi_gl.h b/src/gapi_gl.h index 682d4ff..43289c1 100644 --- a/src/gapi_gl.h +++ b/src/gapi_gl.h @@ -306,30 +306,204 @@ namespace GAPI { -#ifndef FFP - const char SHADER_BASE[] = - #include "shaders/shader.glsl" - ; - - const char SHADER_WATER[] = - #include "shaders/water.glsl" - ; - - const char SHADER_FILTER[] = - #include "shaders/filter.glsl" - ; - - const char SHADER_GUI[] = - #include "shaders/gui.glsl" - ; -#endif - using namespace Core; typedef ::Vertex Vertex; int cullMode, blendMode; +// Shader + #ifndef FFP + const char SHADER_BASE[] = + #include "shaders/shader.glsl" + ; + + const char SHADER_WATER[] = + #include "shaders/water.glsl" + ; + + const char SHADER_FILTER[] = + #include "shaders/filter.glsl" + ; + + const char SHADER_GUI[] = + #include "shaders/gui.glsl" + ; + + const char *DefineName[SD_MAX] = { SHADER_DEFINES(DECL_STR) }; + #endif + + struct Shader { + #ifdef FFP + void init(Core::Pass pass, int *def, int defCount) {} + void deinit() {} + void bind() {} + void setParam(UniformType uType, const vec4 &value, int count = 1) {} + void setParam(UniformType uType, const mat4 &value, int count = 1) {} + void setParam(UniformType uType, const Basis &value, int count = 1) {} + #else + uint32 ID; + int32 uID[uMAX]; + + void init(Core::Pass pass, int *def, int defCount) { + const char *source; + switch (pass) { + case Core::passCompose : + case Core::passShadow : + case Core::passAmbient : source = SHADER_BASE; break; + case Core::passWater : source = SHADER_WATER; break; + case Core::passFilter : source = SHADER_FILTER; break; + case Core::passGUI : source = SHADER_GUI; break; + default : ASSERT(false); LOG("! wrong pass id\n"); return; + } + + char defines[1024]; + sprintf(defines, "#define PASS_%s\n", passNames[pass]); + + for (int i = 0; i < defCount; i++) { + #ifdef _GAPI_GLES + if (def[i] == SD_SHADOW_SAMPLER) + strcat(ext, "#extension GL_EXT_shadow_samplers : require\n"); + #endif + sprintf(defines, "%s#define %s\n", defines, DefineName[def[i]]); + } + + char fileName[255]; + // generate shader file path + if (Core::support.shaderBinary) { + uint32 hash = fnv32(defines, strlen(defines), fnv32(source, strlen(source))); + sprintf(fileName, "%08X.xsh", hash); + } + + ID = glCreateProgram(); + + if (!(Core::support.shaderBinary && linkBinary(fileName))) { // try to load cached shader + if (linkSource(source, defines) && Core::support.shaderBinary) { // compile shader from source and dump it into cache + #ifndef _OS_WEB + GLenum format, size; + glGetProgramiv(ID, GL_PROGRAM_BINARY_LENGTH, (GLsizei*)&size); + char *data = new char[8 + size]; + glGetProgramBinary(ID, size, NULL, &format, &data[8]); + *(int*)(&data[0]) = format; + *(int*)(&data[4]) = size; + Stream::cacheWrite(fileName, data, 8 + size); + delete[] data; + #endif + } + } + + Core::active.shader = this; + glUseProgram(ID); + + for (int st = 0; st < sMAX; st++) { + GLint idx = glGetUniformLocation(ID, (GLchar*)SamplerName[st]); + if (idx != -1) + glUniform1iv(idx, 1, &st); + } + + for (int ut = 0; ut < uMAX; ut++) + uID[ut] = glGetUniformLocation(ID, (GLchar*)UniformName[ut]); + } + + void deinit() { + glDeleteProgram(ID); + } + + bool linkSource(const char *text, const char *defines = "") { + #ifdef _GAPI_GLES + #define GLSL_DEFINE "" + #define GLSL_VERT "" + #define GLSL_FRAG "#extension GL_OES_standard_derivatives : enable\n" + #else + #define GLSL_DEFINE "#version 120\n" + #define GLSL_VERT "" + #define GLSL_FRAG "" + #endif + + const int type[2] = { GL_VERTEX_SHADER, GL_FRAGMENT_SHADER }; + const char *code[2][4] = { + { GLSL_DEFINE GLSL_VERT "#define VERTEX\n", defines, "#line 0\n", text }, + { GLSL_DEFINE GLSL_FRAG "#define FRAGMENT\n", defines, "#line 0\n", text } + }; + + GLchar info[1024]; + + for (int i = 0; i < 2; i++) { + GLuint obj = glCreateShader(type[i]); + glShaderSource(obj, 4, code[i], NULL); + glCompileShader(obj); + + glGetShaderInfoLog(obj, sizeof(info), NULL, info); + if (info[0]) LOG("! shader: %s\n", info); + + glAttachShader(ID, obj); + glDeleteShader(obj); + } + + for (int at = 0; at < aMAX; at++) + glBindAttribLocation(ID, at, AttribName[at]); + + glLinkProgram(ID); + + glGetProgramInfoLog(ID, sizeof(info), NULL, info); + if (info[0]) LOG("! program: %s\n", info); + + return checkLink(); + } + + bool linkBinary(const char *name) { + // non-async code! + char path[255]; + strcpy(path, Stream::cacheDir); + strcat(path, name); + + if (!Stream::exists(path)) + return false; + + Stream *stream = new Stream(path); + if (!stream) + return false; + + GLenum size, format; + stream->read(format); + stream->read(size); + char *data = new char[size]; + stream->raw(data, size); + glProgramBinary(ID, format, data, size); + delete[] data; + delete stream; + + return checkLink(); + } + + bool checkLink() { + GLint success; + glGetProgramiv(ID, GL_LINK_STATUS, &success); + return success != 0; + } + + void bind() { + if (Core::active.shader != this) { + Core::active.shader = this; + glUseProgram(ID); + } + } + + void setParam(UniformType uType, const vec4 &value, int count = 1) { + if (uID[uType] != -1) glUniform4fv(uID[uType], count, (GLfloat*)&value); + } + + void setParam(UniformType uType, const mat4 &value, int count = 1) { + if (uID[uType] != -1) glUniformMatrix4fv(uID[uType], count, false, (GLfloat*)&value); + } + + void setParam(UniformType uType, const Basis &value, int count = 1) { + if (uID[uType] != -1) glUniform4fv(uID[uType], count * 2, (GLfloat*)&value); + } + #endif + }; + + // Texture struct Texture { uint32 ID; @@ -368,7 +542,7 @@ namespace GAPI { glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter ? (mipmaps ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR ) : ( mipmaps ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST )); glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter ? GL_LINEAR : GL_NEAREST); - struct FormatDesc { + static const struct FormatDesc { GLuint ifmt, fmt; GLenum type; } formats[FMT_MAX] = { @@ -599,15 +773,6 @@ namespace GAPI { } else range.aIndex = -1; } - - /* - void unbind() { - if (Core::support.VAO) - glBindVertexArray(Core::active.VAO = 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Core::active.iBuffer = 0); - glBindBuffer(GL_ARRAY_BUFFER, Core::active.vBuffer = 0); - } - */ }; @@ -813,6 +978,10 @@ namespace GAPI { glDeleteRenderbuffers(1, &rtCache[b].items[i].ID); } + void beginFrame() {} + + void endFrame() {} + void resetState() { if (Core::support.VAO) glBindVertexArray(0); @@ -960,14 +1129,14 @@ namespace GAPI { #endif } - void DIP(int iStart, int iCount, Index *iBuffer) { + void DIP(Mesh *mesh, const MeshRange &range) { #ifdef FFP mat4 m = mView * mModel; glMatrixMode(GL_MODELVIEW); glLoadMatrixf((GLfloat*)&m); #endif - glDrawElements(GL_TRIANGLES, iCount, GL_UNSIGNED_SHORT, iBuffer + iStart); + glDrawElements(GL_TRIANGLES, range.iCount, GL_UNSIGNED_SHORT, mesh->iBuffer + range.iStart); } vec4 copyPixel(int x, int y) { diff --git a/src/gapi_gu.h b/src/gapi_gu.h index eff87ae..4fd635c 100644 --- a/src/gapi_gu.h +++ b/src/gapi_gu.h @@ -289,6 +289,10 @@ namespace GAPI { delete[] cmdBuf; } + void beginFrame() {} + + void endFrame() {} + void resetState() {} void bindTarget(Texture *texture, int face) { @@ -377,13 +381,13 @@ namespace GAPI { sceGumLoadMatrix((ScePspFMatrix4*)&mView); } - void DIP(int iStart, int iCount, Index *iBuffer) { + void DIP(Mesh *mesh, const MeshRange &range) { mat4 m = mModel; m.scale(vec3(32767.0f)); sceGumMatrixMode(GU_MODEL); sceGumLoadMatrix((ScePspFMatrix4*)&m); - sceGumDrawArray(GU_TRIANGLES, GU_TEXTURE_16BIT | GU_COLOR_8888 | GU_NORMAL_16BIT | GU_VERTEX_16BIT | GU_INDEX_16BIT | GU_TRANSFORM_3D, iCount, active.iBuffer + iStart, active.vBuffer); + sceGumDrawArray(GU_TRIANGLES, GU_TEXTURE_16BIT | GU_COLOR_8888 | GU_NORMAL_16BIT | GU_VERTEX_16BIT | GU_INDEX_16BIT | GU_TRANSFORM_3D, range.iCount, mesh->iBuffer + range.iStart, mesh->vBuffer); } vec4 copyPixel(int x, int y) { diff --git a/src/inventory.h b/src/inventory.h index 7e6a085..b31d1cd 100644 --- a/src/inventory.h +++ b/src/inventory.h @@ -1107,7 +1107,7 @@ struct Inventory { for (int i = 0; i < COUNT(background); i++) if (!background[i]) - background[i] = new Texture(INVENTORY_BG_SIZE, INVENTORY_BG_SIZE, FMT_RGBA); + background[i] = new Texture(INVENTORY_BG_SIZE, INVENTORY_BG_SIZE, FMT_RGBA, OPT_TARGET); return background[0]; } @@ -1522,12 +1522,12 @@ struct Inventory { Core::whiteTex->bind(sShadow); game->setShader(Core::passCompose, Shader::ENTITY, false, false); - vec3 ambient[6] = { - vec3(0.4f), vec3(0.2f), vec3(0.4f), vec3(0.5f), vec3(0.4f), vec3(0.6f) + vec4 ambient[6] = { + vec4(0.4f), vec4(0.2f), vec4(0.4f), vec4(0.5f), vec4(0.4f), vec4(0.6f) }; for (int i = 0; i < MAX_LIGHTS; i++) { - Core::lightPos[i] = vec3(0, 0, 0); + Core::lightPos[i] = vec4(0, 0, 0, 0); Core::lightColor[i] = vec4(0, 0, 0, 1); } diff --git a/src/level.h b/src/level.h index af8e28d..80751b5 100644 --- a/src/level.h +++ b/src/level.h @@ -11,7 +11,11 @@ #include "trigger.h" #include "inventory.h" -#ifdef _DEBUG +#if defined(_DEBUG) && defined(_GAPI_GL) && !defined(_GAPI_GLES) + #define DEBUG_RENDER +#endif + +#ifdef DEBUG_RENDER #include "debug.h" #endif @@ -1354,7 +1358,7 @@ struct Level : IGame { } setRoomParams(roomIndex, Shader::ROOM, 1.0f, intensityf(level.rooms[roomIndex].ambient), 0.0f, 1.0f, transp == 1); - Shader *sh = Core::active.shader; + GAPI::Shader *sh = Core::active.shader; sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS); sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS); @@ -1391,7 +1395,7 @@ struct Level : IGame { continue; setRoomParams(roomIndex, Shader::SPRITE, 1.0f, 1.0f, 0.0f, 1.0f, true); - Shader *sh = Core::active.shader; + GAPI::Shader *sh = Core::active.shader; sh->setParam(uLightColor, Core::lightColor[0], MAX_LIGHTS); sh->setParam(uLightPos, Core::lightPos[0], MAX_LIGHTS); @@ -1456,7 +1460,7 @@ struct Level : IGame { setMainLight(controller); } else { // sprite - Core::lightPos[0] = vec3(0); + Core::lightPos[0] = vec4(0, 0, 0, 0); Core::lightColor[0] = vec4(0, 0, 0, 1); } @@ -1729,7 +1733,7 @@ struct Level : IGame { bool checkPortal(const TR::Room &room, const TR::Room::Portal &portal, const vec4 &viewPort, vec4 &clipPort) { vec3 n = portal.normal; - vec3 v = Core::viewPos - (room.getOffset() + portal.vertices[0]); + vec3 v = Core::viewPos.xyz() - (room.getOffset() + portal.vertices[0]); if (n.dot(v) <= 0.0f) return false; @@ -1976,7 +1980,7 @@ struct Level : IGame { Core::mLightProj[0] = bias * (Core::mProj * Core::mView); - camera->frustum->pos = Core::viewPos; + camera->frustum->pos = Core::viewPos.xyz(); camera->frustum->calcPlanes(Core::mViewProj); setup(); @@ -2124,7 +2128,7 @@ struct Level : IGame { Core::eye = oldEye; } - #ifdef _DEBUG + #ifdef DEBUG_RENDER void renderDebug() { if (level.isTitle() || inventory.titleTimer > 1.0f) return; @@ -2240,7 +2244,7 @@ struct Level : IGame { // Debug::Level::debugBoxes(level, lara->dbgBoxes, lara->dbgBoxesCount); Core::setDepthTest(true); Core::setBlendMode(bmNone); - /* + /*// render ambient cube Core::validateRenderState(); static int dbg_ambient = 0; @@ -2372,7 +2376,7 @@ struct Level : IGame { if (ambientCache) ambientCache->processQueue(); - if (shadow) + if (shadow && player) renderShadows(player->getRoomIndex()); } diff --git a/src/mesh.h b/src/mesh.h index 17d9844..cbb5c51 100644 --- a/src/mesh.h +++ b/src/mesh.h @@ -30,8 +30,7 @@ struct Mesh : GAPI::Mesh { } void render(const MeshRange &range) { - bind(range); - Core::DIP(range.iStart, range.iCount, iBuffer); + Core::DIP(this, range); } }; diff --git a/src/platform/win/OpenLara.vcxproj b/src/platform/win/OpenLara.vcxproj index 7530e69..9350774 100644 --- a/src/platform/win/OpenLara.vcxproj +++ b/src/platform/win/OpenLara.vcxproj @@ -106,7 +106,7 @@ Console true - openvr_api.lib;opengl32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + openvr_api.lib;d3d9.lib;opengl32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) @@ -149,7 +149,7 @@ true true true - wcrt.lib;openvr_api.lib;opengl32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + wcrt.lib;openvr_api.lib;d3d9.lib;opengl32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) true false false @@ -199,6 +199,7 @@ + diff --git a/src/platform/win/OpenLara.vcxproj.filters b/src/platform/win/OpenLara.vcxproj.filters index 5bd4856..def799d 100644 --- a/src/platform/win/OpenLara.vcxproj.filters +++ b/src/platform/win/OpenLara.vcxproj.filters @@ -41,6 +41,7 @@ + libs\minimp3 diff --git a/src/platform/win/main.cpp b/src/platform/win/main.cpp index 58a6763..2c9dcfc 100644 --- a/src/platform/win/main.cpp +++ b/src/platform/win/main.cpp @@ -401,6 +401,90 @@ void sndInit(HWND hwnd) { } } +HWND hWnd; + +#ifdef _GAPI_GL + HDC hDC; + HGLRC hRC; + + void ContextCreate() { + hDC = GetDC(hWnd); + + PIXELFORMATDESCRIPTOR pfd; + memset(&pfd, 0, sizeof(pfd)); + pfd.nSize = sizeof(pfd); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.cColorBits = 32; + pfd.cRedBits = 8; + pfd.cGreenBits = 8; + pfd.cBlueBits = 8; + pfd.cAlphaBits = 8; + pfd.cDepthBits = 24; + pfd.cStencilBits = 8; + + int format = ChoosePixelFormat(hDC, &pfd); + SetPixelFormat(hDC, format, &pfd); + hRC = wglCreateContext(hDC); + wglMakeCurrent(hDC, hRC); + } + + void ContextDelete() { + wglMakeCurrent(0, 0); + wglDeleteContext(hRC); + ReleaseDC(hWnd, hDC); + } + + void ContextResize() {} + + void ContextSwap() { + SwapBuffers(hDC); + } +#else + D3DPRESENT_PARAMETERS d3dpp; + LPDIRECT3D9 D3D; + LPDIRECT3DDEVICE9 device; + + void ContextCreate() { + memset(&d3dpp, 0, sizeof(d3dpp)); + d3dpp.Windowed = TRUE; + d3dpp.BackBufferCount = 1; + d3dpp.BackBufferWidth = 1; + d3dpp.BackBufferHeight = 1; + d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.hDeviceWindow = hWnd; + d3dpp.EnableAutoDepthStencil = TRUE; + d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + + if (!(D3D = Direct3DCreate9(D3D_SDK_VERSION))) { + LOG("! cant't initialize DirectX"); + return; + } + + if (!SUCCEEDED(D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &device))) { + LOG("! can't create device"); + } + } + + void ContextDelete() { + GAPI::deinit(); + if (device) device->Release(); + if (D3D) D3D->Release(); + } + + void ContextResize() { + d3dpp.BackBufferWidth = Core::width; + d3dpp.BackBufferHeight = Core::height; + device->Reset(&d3dpp); + } + + void ContextSwap() { + if (device->Present(NULL, NULL, NULL, NULL) == D3DERR_DEVICELOST) + ContextResize(); + } +#endif static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { @@ -413,6 +497,7 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPara case WM_SIZE: Core::width = LOWORD(lParam); Core::height = HIWORD(lParam); + ContextResize(); break; case WM_DESTROY: PostQuitMessage(0); @@ -487,32 +572,6 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPara return 0; } -HGLRC glInit(HDC hDC) { - PIXELFORMATDESCRIPTOR pfd; - memset(&pfd, 0, sizeof(pfd)); - pfd.nSize = sizeof(pfd); - pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - pfd.cColorBits = 32; - pfd.cRedBits = 8; - pfd.cGreenBits = 8; - pfd.cBlueBits = 8; - pfd.cAlphaBits = 8; - pfd.cDepthBits = 24; - pfd.cStencilBits = 8; - - int format = ChoosePixelFormat(hDC, &pfd); - SetPixelFormat(hDC, format, &pfd); - HGLRC hRC = wglCreateContext(hDC); - wglMakeCurrent(hDC, hRC); - return hRC; -} - -void glFree(HGLRC hRC) { - wglMakeCurrent(0, 0); - wglDeleteContext(hRC); -} - #ifdef VR_SUPPORT vr::IVRSystem *hmd; vr::TrackedDevicePose_t tPose[vr::k_unMaxTrackedDeviceCount]; @@ -645,10 +704,9 @@ int main(int argc, char** argv) { RECT r = { 0, 0, 1280, 720 }; AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, false); - HWND hWnd = CreateWindow("static", "OpenLara", WS_OVERLAPPEDWINDOW, 0, 0, r.right - r.left, r.bottom - r.top, 0, 0, 0, 0); + hWnd = CreateWindow("static", "OpenLara", WS_OVERLAPPEDWINDOW, 0, 0, r.right - r.left, r.bottom - r.top, 0, 0, 0, 0); - HDC hDC = GetDC(hWnd); - HGLRC hRC = glInit(hDC); + ContextCreate(); #ifdef VR_SUPPORT vrInit(); @@ -694,7 +752,7 @@ int main(int argc, char** argv) { vrCompose(); #endif Core::waitVBlank(); - SwapBuffers(hDC); + ContextSwap(); } #ifdef _DEBUG Sleep(20); @@ -709,8 +767,7 @@ int main(int argc, char** argv) { vrFree(); #endif - glFree(hRC); - ReleaseDC(hWnd, hDC); + ContextDelete(); DestroyWindow(hWnd); #ifdef _DEBUG diff --git a/src/shader.h b/src/shader.h index 6b56568..fe0ac53 100644 --- a/src/shader.h +++ b/src/shader.h @@ -3,192 +3,32 @@ #include "core.h" -struct Shader { - vec4 params[uMAX][4]; +struct Shader : GAPI::Shader { enum Type { DEFAULT = 0, /* shader */ SPRITE = 0, FLASH = 1, ROOM = 2, ENTITY = 3, MIRROR = 4, - /* filter */ FILTER_DOWNSAMPLE = 1, FILTER_GRAYSCALE = 2, FILTER_BLUR = 3, FILTER_MIXER = 4, FILTER_EQUIRECTANGULAR = 5, + /* filter */ FILTER_DOWNSAMPLE = 1, FILTER_GRAYSCALE = 2, FILTER_BLUR = 3, FILTER_EQUIRECTANGULAR = 4, /* water */ WATER_DROP = 0, WATER_STEP = 1, WATER_CAUSTICS = 2, WATER_MASK = 3, WATER_COMPOSE = 4, MAX = 6 }; -#ifdef FFP - Shader(const char *source, const char *defines = "") {} - virtual ~Shader() {} - void bind() {} - void setParam(UniformType uType, const int &value, int count = 1) {} - void setParam(UniformType uType, const float &value, int count = 1) {} - void setParam(UniformType uType, const vec2 &value, int count = 1) {} - void setParam(UniformType uType, const vec3 &value, int count = 1) {} - void setParam(UniformType uType, const vec4 &value, int count = 1) {} - void setParam(UniformType uType, const mat4 &value, int count = 1) {} - void setParam(UniformType uType, const Basis &value, int count = 1) {} -#else - uint32 ID; - int32 uID[uMAX]; - Shader(const char *source, const char *defines = "") { - char fileName[255]; - // generate shader file path - if (Core::support.shaderBinary) { - uint32 hash = fnv32(defines, strlen(defines), fnv32(source, strlen(source))); - sprintf(fileName, "%08X.xsh", hash); - } - - ID = glCreateProgram(); - - if (!(Core::support.shaderBinary && linkBinary(fileName))) // try to load cached shader - if (linkSource(source, defines) && Core::support.shaderBinary) { // compile shader from source and dump it into cache - #ifndef _OS_WEB - GLenum format, size; - glGetProgramiv(ID, GL_PROGRAM_BINARY_LENGTH, (GLsizei*)&size); - char *data = new char[8 + size]; - glGetProgramBinary(ID, size, NULL, &format, &data[8]); - *(int*)(&data[0]) = format; - *(int*)(&data[4]) = size; - Stream::cacheWrite(fileName, data, 8 + size); - delete[] data; - #endif - } - - init(); - } - - bool linkSource(const char *text, const char *defines = "") { - #ifdef _GAPI_GLES - #define GLSL_DEFINE "" - #define GLSL_VERT "" - #define GLSL_FRAG "#extension GL_OES_standard_derivatives : enable\n" - #else - #define GLSL_DEFINE "#version 120\n" - #define GLSL_VERT "" - #define GLSL_FRAG "" - #endif - - const int type[2] = { GL_VERTEX_SHADER, GL_FRAGMENT_SHADER }; - const char *code[2][4] = { - { GLSL_DEFINE GLSL_VERT "#define VERTEX\n", defines, "#line 0\n", text }, - { GLSL_DEFINE GLSL_FRAG "#define FRAGMENT\n", defines, "#line 0\n", text } - }; - - GLchar info[1024]; - - for (int i = 0; i < 2; i++) { - GLuint obj = glCreateShader(type[i]); - glShaderSource(obj, 4, code[i], NULL); - glCompileShader(obj); - - glGetShaderInfoLog(obj, sizeof(info), NULL, info); - if (info[0]) LOG("! shader: %s\n", info); - - glAttachShader(ID, obj); - glDeleteShader(obj); - } - - for (int at = 0; at < aMAX; at++) - glBindAttribLocation(ID, at, AttribName[at]); - - glLinkProgram(ID); - - glGetProgramInfoLog(ID, sizeof(info), NULL, info); - if (info[0]) LOG("! program: %s\n", info); - - return checkLink(); - } - - bool linkBinary(const char *name) { - // non-async code! - char path[255]; - strcpy(path, Stream::cacheDir); - strcat(path, name); - - if (!Stream::exists(path)) - return false; - - Stream *stream = new Stream(path); - if (!stream) - return false; - - GLenum size, format; - stream->read(format); - stream->read(size); - char *data = new char[size]; - stream->raw(data, size); - glProgramBinary(ID, format, data, size); - delete[] data; - delete stream; - - return checkLink(); - } - - bool checkLink() { - GLint success; - glGetProgramiv(ID, GL_LINK_STATUS, &success); - return success != 0; + Shader(Core::Pass pass, int *def, int defCount) : GAPI::Shader() { + init(pass, def, defCount); } virtual ~Shader() { - glDeleteProgram(ID); + deinit(); } - void init() { - Core::active.shader = this; - glUseProgram(ID); - - for (int st = 0; st < sMAX; st++) { - GLint idx = glGetUniformLocation(ID, (GLchar*)SamplerName[st]); - if (idx != -1) - glUniform1iv(idx, 1, &st); - } - - for (int ut = 0; ut < uMAX; ut++) - uID[ut] = glGetUniformLocation(ID, (GLchar*)UniformName[ut]); - - memset(params, 0, sizeof(params)); - } - - void bind() { - if (Core::active.shader != this) { - Core::active.shader = this; - glUseProgram(ID); - } - + void setup() { + bind(); setParam(uViewProj, Core::mViewProj); setParam(uLightProj, Core::mLightProj[0], Core::settings.detail.shadows > Core::Settings::Quality::MEDIUM ? SHADOW_OBJ_MAX : 1); setParam(uViewPos, Core::viewPos); setParam(uParam, Core::params); setParam(uFogParams, Core::fogParams); } - - void setParam(UniformType uType, const int &value, int count = 1) { - if (uID[uType] != -1) glUniform1iv(uID[uType], count, (GLint*)&value); - } - - void setParam(UniformType uType, const float &value, int count = 1) { - if (uID[uType] != -1) glUniform1fv(uID[uType], count, (GLfloat*)&value); - } - - void setParam(UniformType uType, const vec2 &value, int count = 1) { - if (uID[uType] != -1) glUniform2fv(uID[uType], count, (GLfloat*)&value); - } - - void setParam(UniformType uType, const vec3 &value, int count = 1) { - if (uID[uType] != -1) glUniform3fv(uID[uType], count, (GLfloat*)&value); - } - - void setParam(UniformType uType, const vec4 &value, int count = 1) { - if (uID[uType] != -1) glUniform4fv(uID[uType], count, (GLfloat*)&value); - } - - void setParam(UniformType uType, const mat4 &value, int count = 1) { - if (uID[uType] != -1) glUniformMatrix4fv(uID[uType], count, false, (GLfloat*)&value); - } - - void setParam(UniformType uType, const Basis &value, int count = 1) { - if (uID[uType] != -1) glUniform4fv(uID[uType], count * 2, (GLfloat*)&value); - } -#endif }; #endif diff --git a/src/shaders/base.hlsl b/src/shaders/base.hlsl new file mode 100644 index 0000000..3844ffb --- /dev/null +++ b/src/shaders/base.hlsl @@ -0,0 +1,81 @@ +#define MAX_LIGHTS 4 +#define MAX_CONTACTS 15 + +struct VS_INPUT { + float4 aCoord : POSITION; + float4 aNormal : NORMAL; + float4 aTexCoord : TEXCOORD0; + float4 aColor : COLOR0; + float4 aLight : COLOR1; +}; + +struct VS_OUTPUT { + float4 wPos : POSITION; + float3 vCoord : TEXCOORD2; + float4 vTexCoord : TEXCOORD0; + float4 vDiffuse : COLOR0; + float4 vNormal : NORMAL; + float4 vViewVec : TEXCOORD1; + float3 vAmbient : COLOR1; + float4 vLightMap : COLOR2; + float4 vLight : COLOR3; +}; + +float4 uParam : register( c0 ); +float4 uTexParam : register( c1 ); +float4x4 uViewProj : register( c2 ); +float4 uBasis[32 * 2] : register( c6 ); +float4x4 uLightProj : register( c70 ); +float4 uMaterial : register( c102 ); +float4 uAmbient[6] : register( c103 ); +float4 uFogParams : register( c109 ); +float4 uViewPos : register( c110 ); +float4 uLightPos[MAX_LIGHTS] : register( c111 ); +float4 uLightColor[MAX_LIGHTS] : register( c115 ); +float4 uRoomSize : register( c119 ); +float4 uPosScale[2] : register( c120 ); +float4 uContacts[MAX_CONTACTS] : register( c122 ); + +#ifdef VERTEX +float3 mulQuat(float4 q, float3 v) { + return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + v * q.w); +} + +float3 mulBasis(float4 rot, float3 pos, float3 v) { + return mulQuat(rot, v) + pos; +} + +VS_OUTPUT main(VS_INPUT In) { + VS_OUTPUT Out; + + int index = int(In.aCoord.w * 2.0); + float4 rBasisRot = uBasis[index]; + float4 rBasisPos = uBasis[index + 1]; + Out.vCoord = mulBasis(rBasisRot, rBasisPos.xyz, In.aCoord.xyz); + Out.wPos = mul(uViewProj, float4(Out.vCoord, rBasisPos.w)); + + Out.vTexCoord = In.aTexCoord * (1.0 / 32767.0); + Out.vTexCoord.xy *= Out.vTexCoord.zw; + + Out.vDiffuse = float4(In.aColor.xyz * In.aLight.xyz, 1.0); + Out.vNormal = In.aNormal; + Out.vViewVec = float4(uViewPos.xyz - Out.vCoord, 0.0); + Out.vAmbient = float3(0.2, 0.2, 0.2); + Out.vLightMap = float4(1.0, 1.0, 1.0, 0.0); + Out.vLight = float4(0.5, 0.5, 0.5, 0.5); + return Out; +} + +#else // PIXEL + +sampler sDiffuse : register(s0); +sampler sNormal : register(s1); +sampler sReflect : register(s2); +sampler sShadow : register(s3); +sampler sEnvironment : register(s4); +sampler sMask : register(s5); + +float4 main(VS_OUTPUT In) : COLOR0 { + return (In.vDiffuse * tex2D(sDiffuse, In.vTexCoord.xy / In.vTexCoord.zw)).bgra; +} +#endif \ No newline at end of file diff --git a/src/shaders/compile_dx9.bat b/src/shaders/compile_dx9.bat new file mode 100644 index 0000000..b4d26ba --- /dev/null +++ b/src/shaders/compile_dx9.bat @@ -0,0 +1,9 @@ +@echo off +fxc /nologo /T vs_3_0 /O3 /Vn BASE_VS /Fh base_vs.h base.hlsl /DVERTEX +fxc /nologo /T ps_3_0 /O3 /Vn BASE_PS /Fh base_ps.h base.hlsl /DPIXEL +fxc /nologo /T vs_3_0 /O3 /Vn WATER_VS /Fh water_vs.h water.hlsl /DVERTEX +fxc /nologo /T ps_3_0 /O3 /Vn WATER_PS /Fh water_ps.h water.hlsl /DPIXEL +fxc /nologo /T vs_3_0 /O3 /Vn FILTER_VS /Fh filter_vs.h filter.hlsl /DVERTEX +fxc /nologo /T ps_3_0 /O3 /Vn FILTER_PS /Fh filter_ps.h filter.hlsl /DPIXEL +fxc /nologo /T vs_3_0 /O3 /Vn GUI_VS /Fh gui_vs.h gui.hlsl /DVERTEX +fxc /nologo /T ps_3_0 /O3 /Vn GUI_PS /Fh gui_ps.h gui.hlsl /DPIXEL \ No newline at end of file diff --git a/src/shaders/filter.glsl b/src/shaders/filter.glsl index 6b525bb..fdc972b 100644 --- a/src/shaders/filter.glsl +++ b/src/shaders/filter.glsl @@ -57,10 +57,6 @@ uniform vec4 uParam; return color; } - vec4 mixer() { // uParam (lerp factor from diffuse to normal textures, multiply, unused, unused) - return mix(texture2D(sDiffuse, vTexCoord), texture2D(sNormal, vTexCoord), uParam.x) * uParam.y; - } - #ifdef FILTER_EQUIRECTANGULAR uniform samplerCube sEnvironment; @@ -86,10 +82,6 @@ uniform vec4 uParam; return blur(); #endif - #ifdef FILTER_MIXER - return mixer(); - #endif - #ifdef FILTER_EQUIRECTANGULAR return equirectangular(); #endif diff --git a/src/shaders/filter.hlsl b/src/shaders/filter.hlsl new file mode 100644 index 0000000..3844ffb --- /dev/null +++ b/src/shaders/filter.hlsl @@ -0,0 +1,81 @@ +#define MAX_LIGHTS 4 +#define MAX_CONTACTS 15 + +struct VS_INPUT { + float4 aCoord : POSITION; + float4 aNormal : NORMAL; + float4 aTexCoord : TEXCOORD0; + float4 aColor : COLOR0; + float4 aLight : COLOR1; +}; + +struct VS_OUTPUT { + float4 wPos : POSITION; + float3 vCoord : TEXCOORD2; + float4 vTexCoord : TEXCOORD0; + float4 vDiffuse : COLOR0; + float4 vNormal : NORMAL; + float4 vViewVec : TEXCOORD1; + float3 vAmbient : COLOR1; + float4 vLightMap : COLOR2; + float4 vLight : COLOR3; +}; + +float4 uParam : register( c0 ); +float4 uTexParam : register( c1 ); +float4x4 uViewProj : register( c2 ); +float4 uBasis[32 * 2] : register( c6 ); +float4x4 uLightProj : register( c70 ); +float4 uMaterial : register( c102 ); +float4 uAmbient[6] : register( c103 ); +float4 uFogParams : register( c109 ); +float4 uViewPos : register( c110 ); +float4 uLightPos[MAX_LIGHTS] : register( c111 ); +float4 uLightColor[MAX_LIGHTS] : register( c115 ); +float4 uRoomSize : register( c119 ); +float4 uPosScale[2] : register( c120 ); +float4 uContacts[MAX_CONTACTS] : register( c122 ); + +#ifdef VERTEX +float3 mulQuat(float4 q, float3 v) { + return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + v * q.w); +} + +float3 mulBasis(float4 rot, float3 pos, float3 v) { + return mulQuat(rot, v) + pos; +} + +VS_OUTPUT main(VS_INPUT In) { + VS_OUTPUT Out; + + int index = int(In.aCoord.w * 2.0); + float4 rBasisRot = uBasis[index]; + float4 rBasisPos = uBasis[index + 1]; + Out.vCoord = mulBasis(rBasisRot, rBasisPos.xyz, In.aCoord.xyz); + Out.wPos = mul(uViewProj, float4(Out.vCoord, rBasisPos.w)); + + Out.vTexCoord = In.aTexCoord * (1.0 / 32767.0); + Out.vTexCoord.xy *= Out.vTexCoord.zw; + + Out.vDiffuse = float4(In.aColor.xyz * In.aLight.xyz, 1.0); + Out.vNormal = In.aNormal; + Out.vViewVec = float4(uViewPos.xyz - Out.vCoord, 0.0); + Out.vAmbient = float3(0.2, 0.2, 0.2); + Out.vLightMap = float4(1.0, 1.0, 1.0, 0.0); + Out.vLight = float4(0.5, 0.5, 0.5, 0.5); + return Out; +} + +#else // PIXEL + +sampler sDiffuse : register(s0); +sampler sNormal : register(s1); +sampler sReflect : register(s2); +sampler sShadow : register(s3); +sampler sEnvironment : register(s4); +sampler sMask : register(s5); + +float4 main(VS_OUTPUT In) : COLOR0 { + return (In.vDiffuse * tex2D(sDiffuse, In.vTexCoord.xy / In.vTexCoord.zw)).bgra; +} +#endif \ No newline at end of file diff --git a/src/shaders/gui.hlsl b/src/shaders/gui.hlsl new file mode 100644 index 0000000..beff268 --- /dev/null +++ b/src/shaders/gui.hlsl @@ -0,0 +1,49 @@ +#define MAX_LIGHTS 4 +#define MAX_CONTACTS 15 + +struct VS_INPUT { + float4 aCoord : POSITION; + float4 aNormal : NORMAL; + float4 aTexCoord : TEXCOORD0; + float4 aColor : COLOR0; + float4 aLight : COLOR1; +}; + +float4 uParam : register( c0 ); +float4 uTexParam : register( c1 ); +float4x4 uViewProj : register( c2 ); +float4 uBasis[32 * 2] : register( c6 ); +float4x4 uLightProj : register( c70 ); +float4 uMaterial : register( c102 ); +float4 uAmbient[6] : register( c103 ); +float4 uFogParams : register( c109 ); +float4 uViewPos : register( c110 ); +float4 uLightPos[MAX_LIGHTS] : register( c111 ); +float4 uLightColor[MAX_LIGHTS] : register( c115 ); +float4 uRoomSize : register( c119 ); +float4 uPosScale[2] : register( c120 ); +float4 uContacts[MAX_CONTACTS] : register( c122 ); + +struct VS_OUTPUT { + float4 wPos : POSITION; + float2 vTexCoord : TEXCOORD0; + float4 vDiffuse : COLOR0; +}; + +#ifdef VERTEX +VS_OUTPUT main(VS_INPUT In) { + VS_OUTPUT Out; + Out.wPos = mul(uViewProj, float4(In.aCoord.xy * uPosScale[0].zw + uPosScale[0].xy, 0.0, 1.0)); + Out.vTexCoord = In.aTexCoord.xy * (1.0 / 32767.0); + Out.vDiffuse = In.aLight * uMaterial; + return Out; +} + +#else // PIXEL + +sampler sDiffuse : register(s0); + +float4 main(VS_OUTPUT In) : COLOR0 { + return float4(1.0, 1.0, 1.0, 1.0);//(In.vDiffuse * tex2D(sDiffuse, In.vTexCoord.xy)).bgra; +} +#endif \ No newline at end of file diff --git a/src/shaders/shader.glsl b/src/shaders/shader.glsl index eb15259..40f8885 100644 --- a/src/shaders/shader.glsl +++ b/src/shaders/shader.glsl @@ -4,6 +4,11 @@ R"====( precision highp float; #endif +#define MAX_LIGHTS 4 +#define MAX_CONTACTS 15 +#define WATER_FOG_DIST (1.0 / (6.0 * 1024.0)) +#define UNDERWATER_COLOR vec3(0.6, 0.9, 0.9) + #if (defined(PASS_AMBIENT) || defined(PASS_COMPOSE)) && !defined(TYPE_FLASH) varying vec3 vCoord; #endif @@ -15,11 +20,18 @@ varying vec4 vTexCoord; // xy - atlas coords, zw - trapezoidal correction #endif #ifdef OPT_SHADOW + #ifdef OPT_SHADOW_HIGH + #define SHADOW_OBJ_MAX 8 + #define SHADOW_TEXEL vec3(1.0 / 512.0, 1.0 / 256.0, 0.0) + #else + #define SHADOW_OBJ_MAX 1 + #define SHADOW_TEXEL vec3(1.0 / 1024.0, 1.0 / 1024.0, 0.0) + #endif uniform mat4 uLightProj[SHADOW_OBJ_MAX]; #endif uniform mat4 uViewProj; -uniform vec3 uViewPos; +uniform vec4 uViewPos; uniform vec4 uParam; // x - time, y - water height, z - clip plane sign, w - clip plane height uniform vec4 uLightPos[MAX_LIGHTS]; @@ -53,14 +65,14 @@ uniform vec4 uFogParams; #endif #ifdef OPT_AMBIENT - uniform vec3 uAmbient[6]; + uniform vec4 uAmbient[6]; vec3 calcAmbient(vec3 n) { vec3 sqr = n * n; vec3 pos = step(0.0, n); - return sqr.x * mix(uAmbient[1], uAmbient[0], pos.x) + - sqr.y * mix(uAmbient[3], uAmbient[2], pos.y) + - sqr.z * mix(uAmbient[5], uAmbient[4], pos.z); + return sqr.x * mix(uAmbient[1].xyz, uAmbient[0].xyz, pos.x) + + sqr.y * mix(uAmbient[3].xyz, uAmbient[2].xyz, pos.y) + + sqr.z * mix(uAmbient[5].xyz, uAmbient[4].xyz, pos.z); } #endif @@ -93,14 +105,14 @@ uniform vec4 uFogParams; vec4 coord; coord.w = rBasisPos.w; // visible flag - #if defined(TYPE_SPRITE) && defined(ALIGN_SPRITES) + #if defined(TYPE_SPRITE) coord.xyz = mulBasis(rBasisRot, rBasisPos.xyz + aCoord.xyz, vec3(aTexCoord.z, aTexCoord.w, 0.0) * 32767.0); #else coord.xyz = mulBasis(rBasisRot, rBasisPos.xyz, aCoord.xyz); #endif #ifndef PASS_SHADOW - vViewVec = vec4((uViewPos - coord.xyz) * uFogParams.w, coord.y * uParam.z); + vViewVec = vec4((uViewPos.xyz - coord.xyz) * uFogParams.w, coord.y * uParam.z); #endif #ifdef PASS_AMBIENT @@ -120,7 +132,7 @@ uniform vec4 uFogParams; if (uViewPos.y < uParam.y) d = abs((coord.y - uParam.y) / normalize(vViewVec.xyz).y); else - d = length(uViewPos - coord.xyz); + d = length(uViewPos.xyz - coord.xyz); fog = d * WATER_FOG_DIST; #else fog = length(vViewVec.xyz); diff --git a/src/shaders/water.glsl b/src/shaders/water.glsl index 3b3cdaf..08761db 100644 --- a/src/shaders/water.glsl +++ b/src/shaders/water.glsl @@ -4,6 +4,9 @@ R"====( precision highp float; #endif +#define WATER_FOG_DIST (1.0 / (6.0 * 1024.0)) +#define UNDERWATER_COLOR vec3(0.6, 0.9, 0.9) + varying vec3 vCoord; varying vec2 vTexCoord; varying vec4 vProjCoord; @@ -12,10 +15,10 @@ varying vec4 vNewPos; varying vec3 vViewVec; varying vec3 vLightVec; -uniform vec3 uViewPos; +uniform vec4 uViewPos; uniform mat4 uViewProj; uniform vec4 uLightPos; -uniform vec3 uPosScale[2]; +uniform vec4 uPosScale[2]; uniform vec4 uTexParam; uniform vec4 uParam; @@ -29,11 +32,7 @@ uniform sampler2D sNormal; attribute vec4 aCoord; void main() { - #ifdef WATER_USE_GRID - vec3 coord = aCoord.xyz; - #else - vec3 coord = aCoord.xyz * (1.0 / 32767.0); - #endif + vec3 coord = aCoord.xyz * (1.0 / 32767.0); vTexCoord = (coord.xy * 0.5 + 0.5) * uTexParam.zw; @@ -41,14 +40,7 @@ uniform sampler2D sNormal; float height = 0.0; - #ifdef WATER_COMPOSE - #ifdef WATER_USE_GRID - vTexCoord = (coord.xy * (1.0 / 48.0) * 0.5 + 0.5) * uTexParam.zw; - height = clamp(texture2D(sNormal, vTexCoord).x * 2.0, -0.1, 0.1); - #endif - #endif - - vCoord = vec3(coord.x, height, coord.y) * uPosScale[1] + uPosScale[0]; + vCoord = vec3(coord.x, height, coord.y) * uPosScale[1].xyz + uPosScale[0].xyz; vec4 cp = uViewProj * vec4(vCoord, 1.0); @@ -76,7 +68,7 @@ uniform sampler2D sNormal; gl_Position = vec4(coord.xyz, 1.0); #endif #endif - vViewVec = uViewPos - vCoord.xyz; + vViewVec = uViewPos.xyz - vCoord.xyz; vLightVec = uLightPos.xyz - vCoord.xyz; } #else diff --git a/src/shaders/water.hlsl b/src/shaders/water.hlsl new file mode 100644 index 0000000..3844ffb --- /dev/null +++ b/src/shaders/water.hlsl @@ -0,0 +1,81 @@ +#define MAX_LIGHTS 4 +#define MAX_CONTACTS 15 + +struct VS_INPUT { + float4 aCoord : POSITION; + float4 aNormal : NORMAL; + float4 aTexCoord : TEXCOORD0; + float4 aColor : COLOR0; + float4 aLight : COLOR1; +}; + +struct VS_OUTPUT { + float4 wPos : POSITION; + float3 vCoord : TEXCOORD2; + float4 vTexCoord : TEXCOORD0; + float4 vDiffuse : COLOR0; + float4 vNormal : NORMAL; + float4 vViewVec : TEXCOORD1; + float3 vAmbient : COLOR1; + float4 vLightMap : COLOR2; + float4 vLight : COLOR3; +}; + +float4 uParam : register( c0 ); +float4 uTexParam : register( c1 ); +float4x4 uViewProj : register( c2 ); +float4 uBasis[32 * 2] : register( c6 ); +float4x4 uLightProj : register( c70 ); +float4 uMaterial : register( c102 ); +float4 uAmbient[6] : register( c103 ); +float4 uFogParams : register( c109 ); +float4 uViewPos : register( c110 ); +float4 uLightPos[MAX_LIGHTS] : register( c111 ); +float4 uLightColor[MAX_LIGHTS] : register( c115 ); +float4 uRoomSize : register( c119 ); +float4 uPosScale[2] : register( c120 ); +float4 uContacts[MAX_CONTACTS] : register( c122 ); + +#ifdef VERTEX +float3 mulQuat(float4 q, float3 v) { + return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + v * q.w); +} + +float3 mulBasis(float4 rot, float3 pos, float3 v) { + return mulQuat(rot, v) + pos; +} + +VS_OUTPUT main(VS_INPUT In) { + VS_OUTPUT Out; + + int index = int(In.aCoord.w * 2.0); + float4 rBasisRot = uBasis[index]; + float4 rBasisPos = uBasis[index + 1]; + Out.vCoord = mulBasis(rBasisRot, rBasisPos.xyz, In.aCoord.xyz); + Out.wPos = mul(uViewProj, float4(Out.vCoord, rBasisPos.w)); + + Out.vTexCoord = In.aTexCoord * (1.0 / 32767.0); + Out.vTexCoord.xy *= Out.vTexCoord.zw; + + Out.vDiffuse = float4(In.aColor.xyz * In.aLight.xyz, 1.0); + Out.vNormal = In.aNormal; + Out.vViewVec = float4(uViewPos.xyz - Out.vCoord, 0.0); + Out.vAmbient = float3(0.2, 0.2, 0.2); + Out.vLightMap = float4(1.0, 1.0, 1.0, 0.0); + Out.vLight = float4(0.5, 0.5, 0.5, 0.5); + return Out; +} + +#else // PIXEL + +sampler sDiffuse : register(s0); +sampler sNormal : register(s1); +sampler sReflect : register(s2); +sampler sShadow : register(s3); +sampler sEnvironment : register(s4); +sampler sMask : register(s5); + +float4 main(VS_OUTPUT In) : COLOR0 { + return (In.vDiffuse * tex2D(sDiffuse, In.vTexCoord.xy / In.vTexCoord.zw)).bgra; +} +#endif \ No newline at end of file