using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using Microsoft.DirectX.DirectInput;
using WinFont = System.Drawing.Font;
using D3DFont = Microsoft.DirectX.Direct3D.Font;
using Device=Microsoft.DirectX.Direct3D.Device;
using DeviceType=Microsoft.DirectX.Direct3D.DeviceType;
using DInput = Microsoft.DirectX.DirectInput;
using Manager=Microsoft.DirectX.Direct3D.Manager;
namespace blue_dish_te
{
public struct Hrac
{
public float x;
public float y;
}
///
/// Formular, ktery vytvori D3D device a ve smycce se prekresluje
///
public class RenderForm : Form
{
// promenne
private static Device device = null;
private Svet svet = null;
private Kolize kolize = null;
private Microsoft.DirectX.DirectInput.Device mouse = null;
private Microsoft.DirectX.DirectInput.Device keyboard = null;
private int mouseX = 0;
private int mouseY = 10;
private bool drzKrysu = false;
private long tick = 0;
private long LastTick = 0;
private int loopsCount = 0;
private int fps = 0;
private float dobaVykreslovani = 0.5F;
private bool invertMouse = false;
private WinFont frameRateWinFont;
private D3DFont frameRateD3DFont;
private Material material;
private const float camFov = (float) Math.PI / 4;
private const float camNear = 0.4f;
private const float camFar = 200f;
private Hrac hrac;
///
/// uhly pohledu na scenu
///
private float azimuth;
private float zenith;
///
/// Konstruktor nastavi velikost a vlastnosti okna
///
public RenderForm()
{
ComponentResourceManager resources = new ComponentResourceManager(typeof(RenderForm));
ClientSize = new Size(640, 480); //velikost okna
Text = "Blue-dish-te ver 0.1 pre-Alpha";
Icon = ((Icon) (resources.GetObject("$this.Icon")));
//this.FormBorderStyle = FormBorderStyle.FixedSingle; //styl ramecku okna
//MaximizeBox = false; //minim. a maxim. tlacitko schovane
//MinimizeBox = false;
BringToFront();
}
/**
* Zjisteni zda grafika podporuje Hardwarovou akceleraci
* Caps caps = Manager.GetDeviceCaps(0,DeviceType.Hardware );
* if (caps.DeviceCaps.SupportsHardwareTransformAndLight) {
* ano;
* else
* ne;
**/
///
/// Metoda se pokusi inicializovat D3D. V pripade neuspechu vypise na konzoli chybu
///
/// V pripade neuspechu vraci FALSE jinak TRUE
private bool D3DInit()
{
try
{
//otestujeme schopnosti grafiky
Caps DevCaps = Manager.GetDeviceCaps(0, DeviceType.Hardware);
DeviceType DevType = DeviceType.Reference;
CreateFlags DevFlags = CreateFlags.SoftwareVertexProcessing;
if ((DevCaps.VertexShaderVersion >= new Version(2, 0)) && (DevCaps.PixelShaderVersion >= new Version(2, 0)))
{
DevType = DeviceType.Hardware;
if (DevCaps.DeviceCaps.SupportsHardwareTransformAndLight)
{
DevFlags = CreateFlags.HardwareVertexProcessing;
Console.WriteLine("true");
}
}
DevFlags |= CreateFlags.MultiThreaded;
//pripravime parametry
PresentParameters param = new PresentParameters();
param.EnableAutoDepthStencil = true;
param.AutoDepthStencilFormat = DepthFormat.D16;
param.SwapEffect = SwapEffect.Discard;
param.BackBufferCount = 1;
param.BackBufferWidth = this.Size.Width;
param.BackBufferHeight = this.Size.Height;
param.PresentationInterval = PresentInterval.Immediate;
param.BackBufferFormat = Manager.Adapters[0].CurrentDisplayMode.Format;
param.Windowed = true;
//a vytvorime device
device = new Device(0, DevType, this, DevFlags, param);
//osetreni resetovani Device
device.DeviceReset += new EventHandler(DeviceResetEvent);
device.RenderState.CullMode = Cull.CounterClockwise; //orezavani odvracenych sten
device.RenderState.ZBufferEnable = true;
device.RenderState.Lighting = true; //zapnuti svetel
device.RenderState.Ambient = Color.FromArgb(0x40, 0x40, 0x40);
device.RenderState.SpecularEnable = true; //zapnuti spekularnich odlesku
//nastaveni projekcni matice
device.Transform.Projection = Matrix.PerspectiveFovLH(camFov, (float) ClientSize.Width / ClientSize.Height, camNear, camFar);
//zapnuti vyhlazovani textury
device.SamplerState[0].MinFilter = TextureFilter.Anisotropic;
device.SamplerState[0].MagFilter = TextureFilter.Anisotropic;
device.SamplerState[0].AddressU = TextureAddress.Mirror;
device.SamplerState[0].AddressV = TextureAddress.Mirror;
//vytvorime svetla
CreateLights();
//inicializace fontu pro fps
frameRateWinFont = new WinFont(FontFamily.GenericSansSerif, 12);
frameRateD3DFont = new D3DFont(device, frameRateWinFont);
//nacteme svet
svet = new Svet(device);
svet.LoadMap("semestralka.map");
hrac.x = -(svet.startX * 2 + 1);
hrac.y = -(svet.startY * 2 + 1);
//inicializace detekce kolizi
kolize = new Kolize(svet);
//inicializace materialu
material = new Material();
material.Diffuse = Color.White; //nastaveni difuzni barvy materialu
//material.Specular = Color.White; //nastaveni spekularni barvy materialu
material.Ambient = Color.White; //nastaveni ambientni barvy materialu
material.Emissive = System.Drawing.Color.FromArgb(10, 10, 10);
//material.SpecularSharpness = .2f;
Cursor.Position = new Point(Left + Width / 2, Top + Height / 2);
Cursor.Hide();
drzKrysu = true;
return true;
}
catch(DirectXException e) //pokud doslo k vyjimce vrat FALSE
{
Console.WriteLine(e);
return false;
}
}
private void DeviceResetEvent(object caller, EventArgs args)
{
device.RenderState.CullMode = Cull.CounterClockwise; //orezavani odvracenych sten
device.RenderState.ZBufferEnable = true;
device.RenderState.Lighting = true; //zapnuti svetel
device.RenderState.Ambient = Color.FromArgb(0x40, 0x40, 0x40);
device.RenderState.SpecularEnable = true; //zapnuti spekularnich odlesku
//zapnuti vyhlazovani textury
device.SamplerState[0].MinFilter = TextureFilter.Anisotropic;
device.SamplerState[0].MagFilter = TextureFilter.Anisotropic;
device.SamplerState[0].AddressU = TextureAddress.Mirror;
device.SamplerState[0].AddressV = TextureAddress.Mirror;
//nastaveni projekcni matice
device.Transform.Projection = Matrix.PerspectiveFovLH(camFov, (float) ClientSize.Width / ClientSize.Height, camNear, camFar);
//vytvorime znova vsechny objekty, cimz se se znova inicializuji vertexy
svet.ReInitialize(device);
//znovu nastavime svetla
CreateLights();
}
public void CreateLights()
{
//nastaveni svitu z baterky
device.Lights[0].Enabled = true;
device.Lights[0].Type = LightType.Spot; //nastaveni typu svetla na spot
device.Lights[0].Position = new Vector3(-hrac.x - 6 * (float) Math.Sin(-azimuth), 2.05f - 6 * (float) Math.Sin(zenith), -hrac.y - 6 * (float) Math.Cos(-azimuth));
device.Lights[0].Direction = new Vector3((float) Math.Sin(-azimuth), (float) Math.Sin(zenith - 2 * Math.PI / 180), (float) Math.Cos(-azimuth));
device.Lights[0].Diffuse = Color.White; //nastaveni difuzni barvy svetla
device.Lights[0].Specular = Color.Silver; //nastaveni spekularni barvy svetla
device.Lights[0].Ambient = Color.FromArgb(0x40, 0x40, 0x40);
device.Lights[0].Attenuation0 = 0.00025f;
device.Lights[0].Attenuation2 = 0.009f;
device.Lights[0].Falloff = 4f;
device.Lights[0].InnerConeAngle = 32 * (float) Math.PI / 180; //vrcholovy uhel vnitrniho kuzele
device.Lights[0].OuterConeAngle = 36 * (float) Math.PI / 180; //vrcholovy uhel vnejsiho kuzele
device.Lights[0].Falloff = 1; //druh opadu svetla mezi kuzely
device.Lights[0].Range = camFar; //dosah svetla
device.Lights[0].Update();
}
///
/// Vycisti okno a vykresli scenu
///
private void Render()
{
try
{
// nejdriv provedeme vypocet fps
// spustime tick, pokud neni
if (tick == 0)
tick = Environment.TickCount;
dobaVykreslovani = ((float) (Environment.TickCount - LastTick)) / 1000;
LastTick = Environment.TickCount;
// vyprsela 1 vterina?
float delay = (float) Math.Abs((Environment.TickCount - tick) / 1000);
if (delay > 0.5f)
{
fps = (int) (loopsCount / delay);
loopsCount = 0;
tick = Environment.TickCount;
}
//nacteni z klavesnice a mysi
UpdateKeyboard();
UpdateMouse();
device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Black, 1, 0); /// vycisti pamet hloubky a barev
device.BeginScene(); /// zacatek sceny
//upravime pozice a smer svitu baterky
device.Lights[0].Position = new Vector3(-hrac.x - 4 * (float) Math.Sin(-azimuth), 2.05f - 4 * (float) Math.Sin(zenith), -hrac.y - 4 * (float) Math.Cos(-azimuth));
device.Lights[0].Direction = new Vector3((float) Math.Sin(-azimuth), (float) Math.Sin(zenith - 2 * Math.PI / 180), (float) Math.Cos(-azimuth));
device.Lights[0].Update();
//nastavime matici view
device.Transform.View = Matrix.Identity;
device.Transform.View *= Matrix.Translation(hrac.x, -1.85f, hrac.y);
device.Transform.View *= Matrix.RotationY(azimuth);
device.Transform.View *= Matrix.RotationX(zenith);
//nastavime material vsech ploch
device.Material = material;
//vykreslime svet
svet.Render();
//zobrazime fps
printFPS(fps);
device.EndScene(); //konec sceny
device.Present(); //vykresleni
loopsCount++;
}
catch(Exception e)
{
Console.WriteLine(e);
}
}
public bool InputInit()
{
//create keyboard device.
keyboard = new Microsoft.DirectX.DirectInput.Device(SystemGuid.Keyboard);
if (keyboard == null)
{
Console.WriteLine("No keyboard found.");
return false;
}
//create mouse device.
mouse = new Microsoft.DirectX.DirectInput.Device(SystemGuid.Mouse);
if (mouse == null)
{
Console.WriteLine("No mouse found.");
return false;
}
//Set mouse axis mode absolute.
mouse.Properties.AxisModeAbsolute = true;
//set cooperative level.
keyboard.SetCooperativeLevel(this, CooperativeLevelFlags.NonExclusive | CooperativeLevelFlags.Background);
mouse.SetCooperativeLevel(this, CooperativeLevelFlags.NonExclusive | CooperativeLevelFlags.Background);
mouse.SetDataFormat(DeviceDataFormat.Mouse);
//Acquire devices for capturing.
keyboard.Acquire();
mouse.Acquire();
return true;
}
protected override void OnKeyPress(KeyPressEventArgs e)
{
if (e.KeyChar == 'h')
{
//nastvime hrace na startovni pozici
hrac.x = -(svet.startX * 2 + 1);
hrac.y = -(svet.startY * 2 + 1);
azimuth = 0;
zenith = 0;
mouseX = 0;
mouseY = 10;
}
else if (e.KeyChar == 'x')
{
//ukonceni enginu
Close();
Application.Exit();
}
else if (e.KeyChar == 'k')
{
//drzet / nedrzet krysu (mys)
MouseState state = mouse.CurrentMouseState;
drzKrysu = !drzKrysu;
if (drzKrysu)
Cursor.Hide();
else
Cursor.Show();
}
else if (e.KeyChar == 'u')
{
//invertace mysi
invertMouse = !invertMouse;
}
else if (e.KeyChar == 'l')
{
//nacteni nove mapy
try
{
if (drzKrysu)
Cursor.Show();
drzKrysu = false;
OpenFileDialog dialog = new OpenFileDialog();
dialog.Title = "Load map";
dialog.Filter = "Map file|*.map";
dialog.FilterIndex = 0;
if (dialog.ShowDialog() == DialogResult.OK) {
svet = new Svet(device);
svet.LoadMap(dialog.FileName);
kolize = new Kolize(svet);
hrac.x = -(svet.startX * 2 + 1);
hrac.y = -(svet.startY * 2 + 1);
azimuth = 0;
zenith = 0;
mouseX = 0;
mouseY = 10;
}
drzKrysu = true;
Cursor.Hide();
} catch (Exception ex) {
Console.WriteLine("Nastala chyba s dialogem...");
Console.WriteLine(ex);
}
}
}
private void UpdateKeyboard()
{
int kombinace_klaves = 0;
Hrac hrac_novy = hrac;
float rychlostPohybu = 2.5f * dobaVykreslovani;
Key[] keys = keyboard.GetPressedKeys();
if (!drzKrysu)
return;
//Capture pressed keys.
foreach(Key k in keys)
{
if (k == Key.W)
{
hrac_novy.y -= rychlostPohybu * (float) Math.Cos(azimuth);
hrac_novy.x += rychlostPohybu * (float) Math.Sin(azimuth);
kombinace_klaves |= 1;
}
else if (k == Key.S)
{
hrac_novy.y += rychlostPohybu * (float) Math.Cos(azimuth);
hrac_novy.x -= rychlostPohybu * (float) Math.Sin(azimuth);
kombinace_klaves |= 1;
}
else if (k == Key.A)
{
hrac_novy.y += rychlostPohybu * (float) (Math.Cos(azimuth - Math.PI / 2));
hrac_novy.x -= rychlostPohybu * (float) (Math.Sin(azimuth - Math.PI / 2));
kombinace_klaves |= 2;
}
else if (k == Key.D)
{
hrac_novy.y += rychlostPohybu * (float) (Math.Cos(azimuth + Math.PI / 2));
hrac_novy.x -= rychlostPohybu * (float) (Math.Sin(azimuth + Math.PI / 2));
kombinace_klaves |= 2;
}
}
if (kombinace_klaves == 0)
return;
if ((kombinace_klaves & 1) == 1 && (kombinace_klaves & 2) == 2)
{
hrac_novy.x = hrac.x + (hrac_novy.x - hrac.x) / (float) Math.Sqrt(2);
hrac_novy.y = hrac.y + (hrac_novy.y - hrac.y) / (float) Math.Sqrt(2);
}
hrac = kolize.UpravPohyb(hrac, hrac_novy);
//hrac = hrac_novy;
}
private void UpdateMouse()
{
if (!drzKrysu)
return;
//Get Mouse State.
MouseState state = mouse.CurrentMouseState;
if (state.X == 0 && state.Y == 0)
return;
if (state.X != 0)
{
mouseX += state.X;
azimuth = (float) (-((float) mouseX / (Width)) * (2 * Math.PI)); /// vypocet azimutu a zenitu na zaklade abs. polohy kurzoru
}
if (state.Y != 0)
{
mouseY += state.Y;
zenith = (float) (-((float) mouseY / (Height)) * Math.PI / 2);
if (invertMouse)
zenith = -zenith;
if (zenith > Math.PI / 2)
{
zenith = (float) Math.PI / 2;
mouseY -= state.Y;
}
if (zenith < -Math.PI / 2)
{
zenith = (float) -Math.PI / 2;
mouseY -= state.Y;
}
}
if (drzKrysu && (state.X != 0 || state.Y != 0))
Cursor.Position = new Point(Left + Width / 2, Top + Height / 2);
}
private void printFPS(int fps)
{
frameRateD3DFont.DrawText(null, //Advanced parameter
"FPS: " + fps /*+ "; x: " + (-hrac.x) + "; y:" + (-hrac.y) + "; map: " + svet.map[(int) (-hrac.x)/2][(int) (-hrac.y)/2] + "; lx: " + (float) Math.Cos(-azimuth) + "; ly: " + (float) Math.Sin(zenith) + "; lz: " + (float) Math.Sin(-azimuth)*/, // Text to render
ClientRectangle, //Clip text to this rectangle
DrawTextFormat.Left | //Align text to the left of the window
DrawTextFormat.Top | //and to the top
DrawTextFormat.WordBreak, //And break lines if necessary
Color.GreenYellow); //What color to draw the text in
}
///
/// Po spusteni se pokusi inicializovat Direct3D. V pripade uspechu
/// Prekresluje okno a zpracovava zpravy, dokud existuje okno.
///
[STAThreadAttribute]
public static void Main()
{
RenderForm frm = new RenderForm(); //vytvoreni formulare
if (frm.D3DInit() && frm.InputInit()) //pokud se podari inicializovat d3d
{
frm.Show(); //zobrazeni formu
while(frm.Created) //a dokud form existuje
{
frm.Render(); //vykreslovat scenu
Application.DoEvents(); //a zpracovavat zpravy
//System.Threading.Thread.Sleep(400);
}
}
if (device != null)
device.Dispose();
}
}
}