
Blend with 2 textures, shader model 3.0, d3d9, c++98, irrlicht 1.9.0:
Code: Select all
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <irrlicht.h>
#pragma comment(lib, "Irrlicht.lib")
#pragma comment(lib, "winmm.lib")
using namespace irr;
namespace
{
const u32 TRANSITION_DURATION_MS = 1000;
const c8* CROSSFADE_VS =
"float4x4 WorldMatrix; \n"
"float4x4 ViewMatrix; \n"
"float4x4 ProjectionMatrix; \n"
" \n"
"struct VS_INPUT \n"
"{ \n"
" float4 Position : POSITION0; \n"
" float2 TexCoord : TEXCOORD0; \n"
"}; \n"
" \n"
"struct VS_OUTPUT \n"
"{ \n"
" float4 Position : POSITION0; \n"
" float2 TexCoordA : TEXCOORD0; \n"
" float2 TexCoordB : TEXCOORD1; \n"
"}; \n"
" \n"
"VS_OUTPUT vertexMain(VS_INPUT input) \n"
"{ \n"
" VS_OUTPUT output; \n"
" \n"
" float4 worldPosition = \n"
" mul(input.Position, WorldMatrix); \n"
" \n"
" float4 viewPosition = \n"
" mul(worldPosition, ViewMatrix); \n"
" \n"
" output.Position = \n"
" mul(viewPosition, ProjectionMatrix); \n"
" \n"
" output.TexCoordA = input.TexCoord; \n"
" output.TexCoordB = input.TexCoord; \n"
" \n"
" return output; \n"
"} \n";
const c8* CROSSFADE_PS =
"sampler2D SamplerA : register(s0); \n"
"sampler2D SamplerB : register(s1); \n"
" \n"
"float CrossfadeFactor; \n"
" \n"
"float4 pixelMain( \n"
" float2 texCoordA : TEXCOORD0, \n"
" float2 texCoordB : TEXCOORD1) : COLOR0 \n"
"{ \n"
" float4 colorA = \n"
" tex2D(SamplerA, texCoordA); \n"
" \n"
" float4 colorB = \n"
" tex2D(SamplerB, texCoordB); \n"
" \n"
" return lerp( \n"
" colorA, \n"
" colorB, \n"
" saturate(CrossfadeFactor)); \n"
"} \n";
class CrossfadeShaderCallback : public video::IShaderConstantSetCallBack
{
public:
explicit CrossfadeShaderCallback(video::IVideoDriver* driver)
: Driver(driver),
Factor(0.0f)
{}
void OnSetConstants(
video::IMaterialRendererServices* services,
s32 userData)
{
if (!services || !Driver)
return;
const core::matrix4& world =
Driver->getTransform(video::ETS_WORLD);
const core::matrix4& view =
Driver->getTransform(video::ETS_VIEW);
const core::matrix4& projection =
Driver->getTransform(video::ETS_PROJECTION);
services->setVertexShaderConstant(
"WorldMatrix",
world.pointer(),
16);
services->setVertexShaderConstant(
"ViewMatrix",
view.pointer(),
16);
services->setVertexShaderConstant(
"ProjectionMatrix",
projection.pointer(),
16);
services->setPixelShaderConstant(
"CrossfadeFactor",
&Factor,
1);
}
void setFactor(f32 factor)
{
Factor = core::clamp(factor, 0.0f, 1.0f);
}
private:
video::IVideoDriver* Driver;
f32 Factor;
};
s32 CrossfadeMaterialType = -1;
CrossfadeShaderCallback* ShaderCallback = 0;
bool createCrossfadeMaterial(video::IVideoDriver* driver)
{
if (!driver)
return false;
video::IGPUProgrammingServices* gpu =
driver->getGPUProgrammingServices();
if (!gpu)
return false;
ShaderCallback = new CrossfadeShaderCallback(driver);
CrossfadeMaterialType =
gpu->addHighLevelShaderMaterial(
CROSSFADE_VS,
"vertexMain",
video::EVST_VS_3_0,
CROSSFADE_PS,
"pixelMain",
video::EPST_PS_3_0,
ShaderCallback,
video::EMT_SOLID,
0);
if (CrossfadeMaterialType < 0)
{
ShaderCallback->drop();
ShaderCallback = 0;
return false;
}
return true;
}
bool drawMeshCrossfade(
video::IVideoDriver* driver,
scene::ISceneManager* sceneManager,
scene::IMesh* mesh,
video::ITexture* textureA,
video::ITexture* textureB,
f32 factor,
const core::matrix4& worldMatrix)
{
if (!driver ||
!sceneManager ||
!mesh ||
!textureA ||
!textureB ||
!ShaderCallback ||
CrossfadeMaterialType < 0)
{
return false;
}
scene::ICameraSceneNode* camera =
sceneManager->getActiveCamera();
if (!camera)
return false;
ShaderCallback->setFactor(factor);
driver->setTransform(
video::ETS_WORLD,
worldMatrix);
driver->setTransform(
video::ETS_VIEW,
camera->getViewMatrix());
driver->setTransform(
video::ETS_PROJECTION,
camera->getProjectionMatrix());
video::SMaterial material;
material.MaterialType =
static_cast<video::E_MATERIAL_TYPE>(
CrossfadeMaterialType);
material.Lighting = false;
material.ZWriteEnable = video::EZW_ON;
material.ZBuffer = video::ECFN_LESSEQUAL;
material.BackfaceCulling = true;
material.Wireframe = false;
material.setTexture(0, textureA);
material.setTexture(1, textureB);
material.TextureLayer[0].TextureWrapU =
video::ETC_CLAMP;
material.TextureLayer[0].TextureWrapV =
video::ETC_CLAMP;
material.TextureLayer[1].TextureWrapU =
video::ETC_CLAMP;
material.TextureLayer[1].TextureWrapV =
video::ETC_CLAMP;
driver->setMaterial(material);
const u32 bufferCount =
mesh->getMeshBufferCount();
for (u32 i = 0; i < bufferCount; ++i)
{
scene::IMeshBuffer* meshBuffer =
mesh->getMeshBuffer(i);
if (meshBuffer)
driver->drawMeshBuffer(meshBuffer);
}
return true;
}
class EventReceiver : public IEventReceiver
{
public:
EventReceiver()
{
for (u32 i = 0; i < KEY_KEY_CODES_COUNT; ++i)
{
KeyDown[i] = false;
PreviousKeyDown[i] = false;
}
}
bool OnEvent(const SEvent& event)
{
if (event.EventType != EET_KEY_INPUT_EVENT)
return false;
const EKEY_CODE key =
event.KeyInput.Key;
if (key < 0 || key >= KEY_KEY_CODES_COUNT)
return false;
KeyDown[key] =
event.KeyInput.PressedDown;
return false;
}
bool isKeyDown(EKEY_CODE key) const
{
if (key < 0 || key >= KEY_KEY_CODES_COUNT)
return false;
return KeyDown[key];
}
bool wasKeyPressed(EKEY_CODE key)
{
if (key < 0 || key >= KEY_KEY_CODES_COUNT)
return false;
const bool currentlyDown =
KeyDown[key];
const bool pressed =
currentlyDown &&
!PreviousKeyDown[key];
PreviousKeyDown[key] =
currentlyDown;
return pressed;
}
private:
bool KeyDown[KEY_KEY_CODES_COUNT];
bool PreviousKeyDown[KEY_KEY_CODES_COUNT];
};
}
int main()
{
EventReceiver receiver;
SIrrlichtCreationParameters params;
params.DriverType = video::EDT_DIRECT3D9;
params.WindowSize = core::dimension2du(1280, 720);
params.Bits = 32;
params.Fullscreen = false;
params.Stencilbuffer = true;
params.Vsync = true;
params.AntiAlias = 0;
params.EventReceiver = &receiver;
IrrlichtDevice* device =
createDeviceEx(params);
if (!device)
{
MessageBoxA(
0,
"Could not create Irrlicht with Direct3D 9.",
"Error",
MB_OK | MB_ICONERROR);
return 1;
}
device->setWindowCaption(
L"Irrlicht - Crossfade Shader Model 3.0 (Infinite Loop)");
video::IVideoDriver* driver =
device->getVideoDriver();
scene::ISceneManager* sceneManager =
device->getSceneManager();
gui::IGUIEnvironment* gui =
device->getGUIEnvironment();
if (!driver || !sceneManager || !gui)
{
device->drop();
return 1;
}
if (!driver->queryFeature(video::EVDF_VERTEX_SHADER_3_0) ||
!driver->queryFeature(video::EVDF_PIXEL_SHADER_3_0))
{
MessageBoxA(
0,
"GPU does not support Shader Model 3.0.\n"
"Vertex Shader 3.0 and Pixel Shader 3.0 are required.",
"Incompatible Hardware",
MB_OK | MB_ICONERROR);
device->drop();
return 1;
}
if (!createCrossfadeMaterial(driver))
{
MessageBoxA(
0,
"Could not compile or create the Shader Model 3.0 material.",
"Shader Error",
MB_OK | MB_ICONERROR);
device->drop();
return 1;
}
video::ITexture* textureA =
driver->getTexture("../../media/particle.bmp");
video::ITexture* textureB =
driver->getTexture("../../media/particlegreen.jpg");
if (!textureA || !textureB)
{
MessageBoxA(
0,
"Could not find particle.bmp and/or particlegreen.jpg.",
"Missing Textures",
MB_OK | MB_ICONERROR);
ShaderCallback->drop();
ShaderCallback = 0;
device->drop();
return 1;
}
const scene::IGeometryCreator* geometryCreator =
sceneManager->getGeometryCreator();
scene::IMesh* mesh =
geometryCreator->createCubeMesh(
core::vector3df(15.0f, 15.0f, 15.0f));
if (!mesh)
{
ShaderCallback->drop();
ShaderCallback = 0;
device->drop();
return 1;
}
scene::ICameraSceneNode* camera =
sceneManager->addCameraSceneNode(
0,
core::vector3df(0.0f, 20.0f, -70.0f),
core::vector3df(0.0f, 0.0f, 0.0f));
if (!camera)
{
mesh->drop();
ShaderCallback->drop();
ShaderCallback = 0;
device->drop();
return 1;
}
camera->setNearValue(0.1f);
camera->setFarValue(1000.0f);
camera->setFOV(53.13f * core::DEGTORAD);
gui::IGUIFont* font =
gui->getBuiltInFont();
u32 transitionStart =
device->getTimer()->getTime();
f32 factor = 0.0f;
bool goingForward = true;
while (device->run())
{
if (!device->isWindowActive())
{
device->yield();
continue;
}
if (receiver.wasKeyPressed(KEY_SPACE))
{
transitionStart =
device->getTimer()->getTime();
goingForward = true;
factor = 0.0f;
}
const u32 now =
device->getTimer()->getTime();
const u32 elapsed =
now - transitionStart;
const f32 rawFactor =
static_cast<f32>(elapsed) /
static_cast<f32>(TRANSITION_DURATION_MS);
if (goingForward)
{
factor = rawFactor;
if (factor >= 1.0f)
{
factor = 1.0f;
goingForward = false;
transitionStart = now;
}
}
else
{
factor = 1.0f - rawFactor;
if (factor <= 0.0f)
{
factor = 0.0f;
goingForward = true;
transitionStart = now;
}
}
const f32 scaleValue =
1.0f +
0.35f *
static_cast<f32>(
sin(static_cast<f64>(now) * 0.002));
core::matrix4 scaleMatrix;
scaleMatrix.setScale(
core::vector3df(
scaleValue,
scaleValue,
scaleValue));
core::matrix4 rotationMatrix;
rotationMatrix.setRotationDegrees(
core::vector3df(
static_cast<f32>(now) * 0.015f,
static_cast<f32>(now) * 0.030f,
0.0f));
core::matrix4 translationMatrix;
translationMatrix.setTranslation(
core::vector3df(0.0f, 0.0f, 0.0f));
core::matrix4 worldMatrix =
scaleMatrix *
rotationMatrix *
translationMatrix;
sceneManager->setActiveCamera(camera);
camera->render();
driver->beginScene(
true,
true,
video::SColor(255, 35, 40, 50));
const bool rendered =
drawMeshCrossfade(
driver,
sceneManager,
mesh,
textureA,
textureB,
factor,
worldMatrix);
wchar_t status[512];
swprintf(
status,
512,
L"Crossfade: %.3f Direction: %s Scale: %.2f [SPACE: restart] [ESC: exit]",
factor,
goingForward ? L"A->B" : L"B->A",
scaleValue);
if (font)
{
font->draw(
status,
core::rect<s32>(
20,
20,
1200,
60),
rendered
? video::SColor(
255, 255, 255, 255)
: video::SColor(
255, 255, 80, 80));
}
driver->endScene();
if (receiver.isKeyDown(KEY_ESCAPE))
device->closeDevice();
Sleep(1);
}
mesh->drop();
if (ShaderCallback)
{
ShaderCallback->drop();
ShaderCallback = 0;
}
device->drop();
return 0;
}