static void Main(string[] args) { //We choosed OpenGL because it is cross-platform and we only have the openGL shader //So please do not change this unless you change the shader ! IrrlichtDevice device = new IrrlichtDevice(DriverType.Direct3D9, new Dimension2D(640, 480), 32, false, true, true, false); //We set a new working directory device.FileSystem.WorkingDirectory = "../../medias"; device.OnEvent += new OnEventDelegate(device_OnEvent); //We set a basic caption string caption = "Irrlicht .NET CP Shaders and Particles Example"; //We set our handlers Driver = device.VideoDriver; Scene = device.SceneManager; //We have already seen that... The only special thing is the pointless emitter (what a funny name isn't it ?) //Which is detailed just down. Texture fire = Driver.GetTexture("fire.bmp"); ParticleSystemSceneNode particles = Scene.AddParticleSystemSceneNode(false, null, -1); particles.SetEmitter(new PointlessEmitter()); //particles.AddAffector(new PointlessAffector()); particles.SetMaterialTexture(0, fire); particles.SetMaterialType(MaterialType.TransparentAddColor); particles.SetMaterialFlag(MaterialFlag.Lighting, false); particles.ParticleSize = new Dimension2Df(50, 50); particles.ParticlesAreGlobal = false; particles = Scene.AddParticleSystemSceneNode(false, null, -1); particles.SetEmitter(new PointlessEmitter()); //particles.AddAffector(new PointlessAffector()); particles.SetMaterialTexture(0, fire); particles.SetMaterialType(MaterialType.TransparentAddColor); particles.SetMaterialFlag(MaterialFlag.Lighting, false); particles.ParticleSize = new Dimension2Df(50, 50); particles.Position = new Vector3D(0, 400, 0); particles.ParticlesAreGlobal = false; particles = Scene.AddParticleSystemSceneNode(false, null, -1); particles.SetEmitter(new PointlessEmitter()); //particles.AddAffector(new PointlessAffector()); particles.SetMaterialTexture(0, fire); particles.SetMaterialType(MaterialType.TransparentAddColor); particles.SetMaterialFlag(MaterialFlag.Lighting, false); particles.ParticleSize = new Dimension2Df(50, 50); particles.Position = new Vector3D(0, -400, 0); particles.ParticlesAreGlobal = false; //Here we only create 3 cubes and add a texture... Nothing exciting SceneNode cube1, cube2, cube3; cube1 = Scene.AddCubeSceneNode(40f, null, -1); cube2 = Scene.AddCubeSceneNode(40f, null, -1); cube3 = Scene.AddCubeSceneNode(40f, null, -1); cube1.SetMaterialTexture(0, Driver.GetTexture("rockwall.bmp")); cube2.SetMaterialTexture(0, Driver.GetTexture("rockwall.bmp")); cube3.SetMaterialTexture(0, Driver.GetTexture("rockwall.bmp")); //Here comes the fun... We create two low level shaders (taken from Irrlich's shader Example) and we set the base material as //Solid for the first one and transparent for the second int mat = Driver.GPUProgrammingServices.AddShaderMaterialFromFiles("opengl.vsh", "opengl.psh", OnShaderSet, MaterialType.Solid, 0); int mat2 = Driver.GPUProgrammingServices.AddShaderMaterialFromFiles("opengl.vsh", "opengl.psh", OnShaderSet, MaterialType.TransparentAddColor, 0); //And now we add both materials... Notice that no cast is needed because SetMaterialType //Has an overload especially made for shaders ! cube2.SetMaterialType(mat); cube3.SetMaterialType(mat2); cube2.Position = new Vector3D(0, -40, 0); cube3.Position = new Vector3D(0, 40, 0); //We create a fixed cam for our render target scene CameraSceneNode fixedcam = Scene.AddCameraSceneNode(null); fixedcam.Position = new Vector3D(50, 0, -1000); fixedcam.FarValue = 10000f; fixedcam.AddAnimator(Scene.CreateFlyCircleAnimator(fixedcam.Target, 5000f, 0.001f)); //And a fps cam for our main scene CameraSceneNode fpscam = Scene.AddCameraSceneNodeFPS(null, 100f, 400f, false); Scene.ActiveCamera.Position = new Vector3D(50, 0, -1000); Scene.ActiveCamera.FarValue = 10000f; Texture mask = Driver.AddTexture(new Dimension2D(128, 128), "", ColorFormat.A8R8G8B8); //Here is another cool feature from .NET CP //Direct access to textures via Texture.Lock/Unlock and Texture.SetPixel/GetPixel //Uncomment these lines to see the effect :) /*int w = mask.OriginalSize.Width; int h = mask.OriginalSize.Height; double maxdistance = Math.Sqrt(Math.Pow(w, 2) + Math.Pow(h, 2)); mask.Lock(); for (int x = 0; x < w; x++) for (int y = 0; y < h; y++) { double distance = Math.Sqrt(Math.Pow((w - x), 2) + Math.Pow((h - y), 2)); double coeff = distance / maxdistance; int color = (int)(255 - (255 * coeff)); Color pixel = new Color((int)(color / 1.5), (int)(color / 1.5), (int)(color / 2), (int)(color / 2)); mask.SetPixel(x, y, pixel); } mask.Unlock(); //Again a useful feature... Direct texture saving to common formats such as png,jpg,bmp or gif... //Without coding anything, your texture is directly saved in Irrlicht's working directory ! mask.Save("image.png");*/ //You may have noticed that GetPixel/SetPixel is very slow even if you lock the texture. //Another insecure but quite faster way to proceed is to convert our lock to a pointer. //It needs unsafe code but works very fast... //However it is very unsecure and you must know perfectly what you are doing... //That's why Modify/Retrieve exists (look down) /*int w = mask.OriginalSize.Width; int h = mask.OriginalSize.Height; double maxdistance = Math.Sqrt(Math.Pow(w, 2) + Math.Pow(h, 2)); IntPtr lockresult = mask.Lock(); unsafe { int* directacces = (int*)(void*)lockresult; int pitch = mask.Pitch / 4; for (int x = 0; x < w; ++x) for (int y = 0; y < h; ++y) { double distance = Math.Sqrt(Math.Pow((w - x), 2) + Math.Pow((h - y), 2)); double coeff = distance / maxdistance; int color = (int)(255 - (255 * coeff)); Color pixel = new Color((int)(color / 1.5), (int)(color / 1.5), (int)(color / 2), (int)(color / 2)); directacces[x + y * pitch] = pixel.NativeColor; } } mask.Unlock();*/ //Here is the SAFEST AND FASTEST way to modify our texture. //A simple delegate which takes the coords of the pixel and returns the color //It is called on each pixel and you can even return false if you don't want to change the pixel. //We can now create our mask without speed or compatibility issue ! int w = mask.OriginalSize.Width / 2; int h = mask.OriginalSize.Height / 2; double maxdistance = Math.Sqrt(Math.Pow(w, 2) + Math.Pow(h, 2)); //We create a delegate to modify each pixel ModifyPixel del = delegate(int x, int y, out Color col) { //Here is our formula... You can modify it as you wish, this is just an example ! double distance = Math.Sqrt(Math.Pow((w - x), 2) + Math.Pow((h - y), 2)); double coeff = distance / maxdistance; int color = (int)(255 - (255 * coeff)); //We now set the out color col = new Color((int)(color / 1.5), (int)(color / 1.5), (int)(color / 2), (int)(color / 2)); //And we return true since we created a color. //If you return false, the current pixel won't be modified ! return true; }; //And we modify our texture with our delegate mask.Modify(del); //Uncomment this line to save our mask on a portable network graphic file ! //You do not need to know jpg, bmp, gif, png... formats since they are converted automatically //mask.Save("mask.png"); Console.WriteLine(); Console.WriteLine("============================================"); Console.WriteLine("Features List :"); Console.WriteLine(); for (VideoDriverFeature feat = 0; feat < VideoDriverFeature.Count; feat++) Console.WriteLine(feat + " = " + Driver.QueryFeature(feat)); Console.WriteLine("============================================"); //Here is our logo Texture logo = Driver.GetTexture("NETCPlogo.png"); //Here is another feature, RenderTarget Texture renderTarget = Driver.CreateRenderTargetTexture(new Dimension2D(320, 240)); int lastfps = -1, fps = 0; while (device.Run() && !Exit) { Driver.BeginScene(true, true, Color.Gray); //Driver.SetRenderTarget(renderTarget, true, true, Color.TransparentBlue); //Scene.ActiveCamera = fixedcam; //Scene.DrawAll(); //Driver.SetRenderTarget(null, true, true, Color.Gray); Scene.ActiveCamera = fpscam; Scene.DrawAll(); //Ok, seems like Irrlicht 1.3.1 doesn't like drawing render target on OpenGL //I guess we will disable this for now... //Driver.Draw2DImage(renderTarget, new Position2D(0, 0), false); Driver.Draw2DImage(mask, new Rect(new Position2D(), Driver.ScreenSize), new Rect(new Position2D(), mask.OriginalSize), Color.White, true); //And finally our logo is painted Driver.Draw2DImage(logo, new Position2D(0, Driver.ScreenSize.Height - logo.OriginalSize.Height), new Rect(new Position2D(0, 0), logo.OriginalSize), Color.White, true); Driver.EndScene(); fps = Driver.FPS; if(fps != lastfps) { device.WindowCaption = caption + " - FPS : " + fps; lastfps = fps; } } device.Close(); }
public TextureManager(Viewer viewer) : base(viewer, -1) { this.viewer = viewer; driver = Reference.VideoDriver; device = Reference.Device; imagefolder = Util.TextureFolder; m_user = Reference.Viewer.ProtocolManager.AvatarConnection; m_user.OnImageReceived += imageReceivedCallback; if (!driver.QueryFeature(VideoDriverFeature.PixelShader_1_1) && !driver.QueryFeature(VideoDriverFeature.ARB_FragmentProgram_1)) { device.Logger.Log("WARNING: Pixel shaders disabled \n" + "because of missing driver/hardware support."); shaderYN=false; } if (!driver.QueryFeature(VideoDriverFeature.VertexShader_1_1) && !driver.QueryFeature(VideoDriverFeature.ARB_FragmentProgram_1)) { device.Logger.Log("WARNING: Vertex shaders disabled \n" + "because of missing driver/hardware support."); shaderYN = false; } if (shaderYN) { GPUProgrammingServices gpu = driver.GPUProgrammingServices; if (gpu != null) { OnShaderConstantSetDelegate callBack = OnSetConstants; newMaterialType1 = gpu.AddHighLevelShaderMaterial(GOOCH_VERTEX_GLSL,"main",VertexShaderType._1_1, GOOCH_FRAG_GLSL,"main", PixelShaderType._1_1, callBack, MaterialType.Solid, 0); } } }