📄 renderwindow.cs
字号:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing.Imaging;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using System.Reflection;
using System.IO;
using System.Threading;
namespace BilevelTextureMagnification
{
/// <summary>
/// Non-modal 3D preview window
/// </summary>
public class RenderWindow : System.Windows.Forms.Form
{
private System.ComponentModel.Container components = null;
private Texture optimizedTexture, hiResTexture;
private Device myDevice;
private VertexBuffer myVertexBuffer;
private Effect myEffect;
private VertexDeclaration myVertexDeclaration;
private RenderWindowThread myThread;
private double time = 0.0;
private System.Windows.Forms.MenuItem viewMenu;
private System.Windows.Forms.MenuItem viewInputMenuItem;
private System.Windows.Forms.MenuItem viewOutputMenuItem;
private System.Windows.Forms.MenuItem viewThresholdedMenuItem;
private System.Windows.Forms.MenuItem animateMenu;
private System.Windows.Forms.MenuItem animateOnMenuItem;
private System.Windows.Forms.MainMenu mainMenu;
internal static RenderWindow Create()
{
RenderWindowThread t = new RenderWindowThread();
return t.Window;
}
private class RenderWindowThread
{
private RenderWindow window;
private bool isReady = false;
private Thread t;
public RenderWindowThread()
{
t = new Thread(new ThreadStart(start));
t.Priority = ThreadPriority.Lowest;
t.Start();
}
private void start()
{
window = new RenderWindow(this);
isReady = true;
Application.Run(window);
}
public RenderWindow Window
{
get
{
while(!isReady || !window.Created)
{
Thread.Sleep(10);
}
return window;
}
}
public void Kill()
{
window.Close();
t.Join();
}
}
internal void Kill()
{
myThread.Kill();
}
private RenderWindow(RenderWindowThread t)
{
myThread = t;
InitializeComponent();
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, true);
PresentParameters presentationParameters = new PresentParameters();
presentationParameters.Windowed = true;
presentationParameters.SwapEffect = SwapEffect.Discard;
DeviceType dt = DeviceType.Hardware;
if(Manager.GetDeviceCaps(0, DeviceType.Hardware).PixelShaderVersion.Major < 3)
{
dt = DeviceType.Reference;
Text += " (emulated in SW)";
}
myDevice = new Device(0, dt, this, CreateFlags.HardwareVertexProcessing, presentationParameters);
// gamma-correct rendering
myDevice.RenderState.SrgbWriteEnable = true;
Assembly assem = Assembly.GetAssembly(typeof(RenderWindow));
Stream st = assem.GetManifestResourceStream("BilievelTextureMagnification.Shader.fx");
myEffect = Effect.FromStream(myDevice, st, null, null, ShaderFlags.None, null);
st.Close();
st = null;
myEffect.Technique = "threshold";
VertexElement[] vertexElements = new VertexElement[]
{
new VertexElement(0, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Position, 0),
new VertexElement(0, 3*4, DeclarationType.Float2, DeclarationMethod.Default, DeclarationUsage.TextureCoordinate, 0),
new VertexElement(0, 5*4, DeclarationType.Float2, DeclarationMethod.Default, DeclarationUsage.TextureCoordinate, 1),
VertexElement.VertexDeclarationEnd
};
myVertexDeclaration = new VertexDeclaration(myDevice, vertexElements);
}
internal void SetBaseTexture(int[,] optimizedArray, Bitmap hiResBitmap)
{
lock(this)
{
if(optimizedTexture != null)
{
optimizedTexture.Dispose();
optimizedTexture = null;
}
if(hiResTexture != null)
{
hiResTexture.Dispose();
hiResTexture = null;
}
if(hiResTexture == null)
{
// The obvious solution would be:
// hiResTexture = new Texture(myDevice, hiResBitmap, Usage.AutoGenerateMipMap, Pool.Managed);
// But that doesn't work for reading.
int wHi = hiResBitmap.Width;
int hHi = hiResBitmap.Height;
int maxMipLevel = (int)(1.5 + Math.Log(Math.Min(wHi, hHi), 2.0));
hiResTexture = new Texture(myDevice, wHi, hHi, maxMipLevel, Usage.None, Format.L8, Pool.Managed);
byte[,] hiResTextureArray = (byte[,])hiResTexture.LockRectangle(typeof(byte), 0, LockFlags.None, new int[]{hHi, wHi});
for(int j = 0; j < hHi; j++)
{
for(int i = 0; i < wHi; i++)
{
hiResTextureArray[j, i] = hiResBitmap.GetPixel(i, j).R;
}
}
hiResTexture.UnlockRectangle(0);
TextureLoader.FilterTexture(hiResTexture, 0, Filter.Box);
}
int w = optimizedArray.GetLength(1);
int h = optimizedArray.GetLength(0);
int downsampling = hiResTexture.GetLevelDescription(0).Width / w;
int levelOffset = (int)(0.5 + Math.Log(downsampling, 2.0));
optimizedTexture = new Texture(myDevice, w, h, hiResTexture.LevelCount - levelOffset, 0, Format.L8, Pool.Managed);
// skip the first level; that's filled dynamically
for(int level = 1; level < hiResTexture.LevelCount - levelOffset; level++)
{
int scale = (int)(0.5 + Math.Pow(2.0, level));
byte[,] originalTextureArray = (byte[,])hiResTexture.LockRectangle(typeof(byte), level + levelOffset, LockFlags.ReadOnly, new int[]{h/scale, w/scale});
byte[,] optimizedTextureArray = (byte[,])optimizedTexture.LockRectangle(typeof(byte), level, LockFlags.None, new int[]{h/scale, w/scale});
int wLevel = w / scale;
int hLevel = h / scale;
for(int j = 0; j < hLevel; j++)
{
for(int i = 0; i < wLevel; i++)
{
int x = optimizedTextureArray[j, i];
optimizedTextureArray[j, i] = (byte)originalTextureArray[j, i];
}
}
optimizedTexture.UnlockRectangle(level);
hiResTexture.UnlockRectangle(level + levelOffset);
}
if(myVertexBuffer != null)
{
myVertexBuffer.Dispose();
}
myVertexBuffer = new VertexBuffer(typeof(DualTextureVertex), 4, myDevice, Usage.WriteOnly, 0, Pool.Managed);
DualTextureVertex[] myVertexData = new DualTextureVertex[4];
float aspectRatio = h/(float)w;
myVertexData[0] = new DualTextureVertex(-1.0f, aspectRatio, 0.0f, 0.0f, 0.0f, 0, 0);
myVertexData[1] = new DualTextureVertex(-1.0f, -aspectRatio, 0.0f, 0.0f, 1.0f, 0, h);
myVertexData[2] = new DualTextureVertex( 1.0f, aspectRatio, 0.0f, 1.0f, 0.0f, w, 0);
myVertexData[3] = new DualTextureVertex( 1.0f, -aspectRatio, 0.0f, 1.0f, 1.0f, w, h);
myVertexBuffer.SetData(myVertexData, 0, LockFlags.None);
}
}
internal void SetTexture(int[,] optimizedArray, Bitmap hiResBitmap)
{
lock(this)
{
if(optimizedTexture == null || optimizedTexture.Disposed)
{
return; // something went wrong
}
int w = optimizedArray.GetLength(1);
int h = optimizedArray.GetLength(0);
SurfaceDescription sd = optimizedTexture.GetLevelDescription(0);
if(w != sd.Width || h != sd.Height) // Out-of-date texture? (Didn't call SetBaseTexture first?)
{
return;
}
byte[,] optimizedtextureArray = (byte[,])optimizedTexture.LockRectangle(typeof(byte), 0, LockFlags.None, new int[]{h, w});
int wLevel = optimizedtextureArray.GetLength(1);
int hLevel = optimizedtextureArray.GetLength(0);
for(int j = 0; j < hLevel; j++)
{
for(int i = 0; i < wLevel; i++)
{
optimizedtextureArray[j, i] = (byte)(optimizedArray[j, i]);
}
}
optimizedTexture.UnlockRectangle(0);
}
}
internal void SaveTexture(string fileName)
{
lock(this)
{
TextureLoader.Save(fileName, ImageFileFormat.Dds, optimizedTexture);
}
}
// Called by RenderWindowThread. Don't call from somewhere else.
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
lock(this)
{
if(myDevice == null || myVertexBuffer == null)
{
return;
}
else if(animateOnMenuItem.Checked)
{
time += 0.5; // in theory, this does _not_ work indefinitely long
}
// float s = (float)(3.0 + 2.95*Math.Sin(1.4+0.2941*time));
myDevice.Transform.World =
//Matrix.Scaling(s, s, s) *
Matrix.RotationX((float)(0.9*Math.Sin(0.3+0.3175*time)))
* Matrix.RotationY((float)(0.9*Math.Sin(0.2+0.2923*time)))
* Matrix.RotationZ((float)(0.7*Math.Sin(0.1+0.2843*time)))
* Matrix.Translation((float)(0.2*Math.Sin(0.3423*time)), (float)(0.2*Math.Sin(0.2712*time)), (float)(11.0-11.0*Math.Sin(0.2737*time)));
myDevice.Clear(ClearFlags.Target, Color.LightBlue, 1.0f, 0);
myDevice.BeginScene();
myDevice.Transform.Projection = Matrix.PerspectiveFovLH(0.3f, ClientSize.Width/(float)((ClientSize.Height != 0) ? ClientSize.Height : 1), 0.01f, 100.0f);
myDevice.Transform.View = Matrix.LookAtLH(new Vector3(0.0f, 0.0f, -2.0f), new Vector3(), new Vector3(0.0f, 1.0f, 0.0f));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -