Ok here is the device creation code
var form = new RenderForm("HexMap Demo");
form.WindowState = FormWindowState.Maximized;
// DirectX DXGI 1.1 factory
SharpDX.DXGI.Factory1 factory1 = new SharpDX.DXGI.Factory1();
// The 1st graphics adapter
Adapter1 adapter1 = factory1.GetAdapter1(0);
AdapterDescription1 adesc = adapter1.Description1;
var description = new SwapChainDescription()
{
BufferCount = 1,
Usage = Usage.RenderTargetOutput,
OutputHandle = form.Handle,
IsWindowed = true,
ModeDescription = new ModeDescription(0, 0, new Rational(60, 1), Format.R8G8B8A8_UNorm),
SampleDescription = new SampleDescription(1, 0),
Flags = SwapChainFlags.AllowModeSwitch,
SwapEffect = SwapEffect.Discard
};
Device device;
SwapChain swapChain;
FeatureLevel[] featureLevels = new FeatureLevel[1];
featureLevels[0] = FeatureLevel.Level_11_0;
Device.CreateWithSwapChain(DriverType.Hardware,DeviceCreationFlags.Debug | DeviceCreationFlags.BgraSupport, description, out device, out swapChain);
var deviceDebug = new DeviceDebug(device); // device must have been created with Debug flag
// create a view of our render target, which is the backbuffer of the swap chain we just created
RenderTargetView renderView;
using (var resource = Resource.FromSwapChain<Texture2D>(swapChain, 0))
renderView = new RenderTargetView(device, resource);
// setting a viewport is required if you want to actually see anything
var context = device.ImmediateContext;
var viewport = new ViewportF(0, 0, form.ClientSize.Width, form.ClientSize.Height);
// Create Depth Buffer & View
var depthBuffer = new Texture2D(device, new Texture2DDescription()
{
Format = Format.D32_Float_S8X24_UInt,
ArraySize = 1,
MipLevels = 1,
Width = form.ClientSize.Width,
Height = form.ClientSize.Height,
SampleDescription = new SampleDescription(1, 0),
Usage = ResourceUsage.Default,
BindFlags = BindFlags.DepthStencil,
CpuAccessFlags = CpuAccessFlags.None,
OptionFlags = ResourceOptionFlags.None
});
var depthView = new DepthStencilView(device, depthBuffer);
context.OutputMerger.SetTargets(depthView, renderView);
ViewportF[] viewports = new ViewportF[1];
viewports[0] = viewport;
context.Rasterizer.SetViewports(viewports);
Here is the render loop:
public static void Render()
{
elapsedTime += GameTime.ElapsedTimeLastUpdate;
if (maxFrameRate > 0 && ticksPerFrame > elapsedTime.Ticks)
return;
context.ClearDepthStencilView(depthView, DepthStencilClearFlags.Depth, 1.0f, 0);
context.ClearRenderTargetView(renderTarget, ClearColor);
foreach (DrawableGameComponent comp in drawableGameComponents)
{
if (comp.Enabled)
comp.Render();
}
swapChain.Present(0, PresentFlags.None);
elapsedTime = TimeSpan.Zero;
}
Here is the part where I draw things:
void drawHexChunks()
{
//Take a snapshot of the camera properties so that they don't change in mid draw
Vector2 cameraPos = new Vector2(camera.Position.X, camera.Position.Z);
Matrix projectionView = camera.ProjectionView;
Vector3 vecEye = camera.Position;
DataBox box = Game.GraphicsDevice.ImmediateContext.MapSubresource(perFrameBuffer, 0, MapMode.WriteDiscard, SharpDX.Direct3D11.MapFlags.None);
var cb = new ProjectionViewBuffer();
cb.ProjectionView = projectionView;
timeValue = (timeValue + (float)GameTime.ElapsedTimeLastUpdate.Ticks * 0.00001f) % 1.0f;
cb.Time = timeValue;
//cb.VecEye = new Vector4(vecEye, 1);
//cb.LightDirection = new Vector4(0.0f, 0.6f, -0.9f, 1);
//cb.LightColor = new Vector4(1.0f, 1.0f, 1.0f, 1.0f);
Utilities.Write(box.DataPointer, ref cb);
Game.GraphicsDevice.ImmediateContext.UnmapSubresource(perFrameBuffer, 0);
Game.GraphicsDevice.ImmediateContext.OutputMerger.SetBlendState(solidBlendState);
Game.GraphicsDevice.ImmediateContext.OutputMerger.SetDepthStencilState(normalDepthState);
Game.GraphicsDevice.ImmediateContext.Rasterizer.State = rasterStateSolid;
Point mapCoords = HexTile.CalculateMapCoordsFromPosition(vecEye);
Point cameraCoords = new Point(mapCoords.X / HexMapChunk.Size, mapCoords.Y / HexMapChunk.Size);
var context = Game.GraphicsDevice.ImmediateContext;
//context.InputAssembler.InputLayout = hexSidesInputLayout;
//context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
//context.VertexShader.Set(hexSidesVS);
//context.VertexShader.SetConstantBuffer(0, perFrameBuffer);
//context.PixelShader.Set(hexSidesPS);
//context.PixelShader.SetConstantBuffer(0, perFrameBuffer);
////context.PixelShader.SetShaderResource(0, riverTextureView);
////context.PixelShader.SetShaderResource(1, riverNormalView);
////context.PixelShader.SetSampler(0, samLinear);
//foreach (HexMapChunk chunk in chunksInView) //chunksInView determined in update function
//{
// chunk.DrawHexSides(hexSidesBuffer);
//}
context.InputAssembler.InputLayout = hexTopInputLayout;
context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
context.VertexShader.Set(hexTopVS);
context.VertexShader.SetConstantBuffer(0, perFrameBuffer);
context.PixelShader.Set(hexTopPS);
context.PixelShader.SetConstantBuffer(0, perFrameBuffer);
context.PixelShader.SetConstantBuffer(1, terrainColorsBuffer);
context.PixelShader.SetShaderResource(0, basicTextureView);
//context.PixelShader.SetShaderResource(1, gradientView);
context.PixelShader.SetSampler(0, samLinear);
foreach (HexMapChunk chunk in chunksInView) //chunksInView determined in update function
{
chunk.DrawHexTop(hexTopBuffer);
}
//Game.GraphicsDevice.ImmediateContext.Rasterizer.State = rasterStateFluid;
//Game.GraphicsDevice.ImmediateContext.OutputMerger.SetBlendState(transparentBlendState);
//Game.GraphicsDevice.ImmediateContext.OutputMerger.SetDepthStencilState(decalDepthState);
//foreach (HexMapChunk chunk in chunksInView) //chunksInView determined in update function
//{
// chunk.DrawHexFluid(hexTopBuffer);
//}
//context.InputAssembler.InputLayout = riverInputLayout;
//context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleList;
//context.VertexShader.Set(riverVS);
//context.VertexShader.SetConstantBuffer(0, perFrameBuffer);
//context.PixelShader.Set(riverPS);
//context.PixelShader.SetConstantBuffer(0, perFrameBuffer);
//context.PixelShader.SetShaderResource(0, gradientView);
//context.PixelShader.SetSampler(0, samLinear);
//foreach (HexMapChunk chunk in rivChunksInView) //chunksInView determined in update function
//{
// chunk.DrawRivers(riverSideBuffer);
//}
}
Next is a screenshot of the result of only drawing the hex tops. I will post a png this time:
[attachment=22366:HexProb.png]
EDIT:
I forgot to post the shader for the hexTops. It's pretty basic, only that there is a constant buffer that holds the color info for each terrain type for color cycling etc. it is indexed with the texture array index. I used to draw rivers directly in this shader, but I didn't like the results:
#define MAX_TERRAINS 50
cbuffer PerFrameBuffer : register(b0)
{
//float4x4 World; This is just the identity matrix, so not needed
float4x4 ViewProjection;
float time;
};
//Texture2DArray hexTextures : register(t0);
Texture2DArray hexTexture : register(t0);
//Texture1D gradTex : register(t1);
SamplerState samLinear;
struct TerrainColor
{
float4 forecolor1;
float4 forecolor2;
float4 backcolor1;
float4 backcolor2;
float forecycle;
float backcycle;
};
cbuffer TerrainColorBuffer : register(b1)
{
TerrainColor TerrainColors[MAX_TERRAINS];
};
struct VertexInput
{
//imediate data
float4 PositionLocal : POSITION0;
float4 Bary : POSITION1; //w component contains edge code for how to handle edge drawing
//int sideIndex : BLENDINDICES0;
//instance data
float4 Translation : POSITION2; //w component contains texture index!
// float4 RiverData[6] : TEXCOORD0;
};
struct VertexOutput
{
float4 PositionH : SV_POSITION;
float4 Bary : POSITION1;
float3 TexCoord : TEXCOORD0;
//float RivTexCoord : TEXCOORD1;
//float RivSize : TEXCOORD2;
//float RivClockwise : TEXCOORD3;
//float RivColor : TEXCOORD4;
};
VertexOutput VS(VertexInput vin)
{
VertexOutput vout;
//float3 positionWorld = vin.PositionLocal + Translation.xyz;
float3 positionWorld = vin.PositionLocal.xyz;
positionWorld.x += vin.Translation.x;
positionWorld.y += vin.Translation.y;
positionWorld.z += vin.Translation.z;
vout.PositionH = mul(float4(positionWorld,1.0f),ViewProjection);
vout.TexCoord.x = vin.PositionLocal.x * 0.5f + 0.5f;
vout.TexCoord.y = vin.PositionLocal.z * 0.5f + 0.55f;
vout.TexCoord.z = vin.Translation.w;
vout.Bary = vin.Bary;
//vout.RivTexCoord = max(vin.Bary.z,vin.Bary.x);
//vout.RivSize = vin.RiverData[vin.sideIndex].x;
//vout.RivClockwise = vin.RiverData[vin.sideIndex].y;
return vout;
}
float4 PS(VertexOutput input ) : SV_Target
{
static const float PI = 3.14159265f;
float4 samplecolor = hexTexture.Sample(samLinear,input.TexCoord);
int terrainIndex = (int)input.TexCoord.z;
float sample = samplecolor.r;
//float sample = 1.0f;
float inversesample = 1.0f - sample;
float foredrift = sin((time * PI * TerrainColors[terrainIndex].forecycle * 2.0f)) * 0.5f + 0.5f;
// float inverseforedrift = 1.0f - foredrift;
float backdrift = sin((time * PI * TerrainColors[terrainIndex].backcycle * 2.0f)) * 0.5f + 0.5f;
// float inversebackdrift = 1.0f - backdrift;
float4 back = lerp(TerrainColors[terrainIndex].backcolor1,TerrainColors[terrainIndex].backcolor2,backdrift);
float4 fore = lerp(TerrainColors[terrainIndex].forecolor1,TerrainColors[terrainIndex].forecolor2,foredrift);
float4 color = back * sample + fore * inversesample;
float shade = 1.0f;
// float4 rivColor = float4(0.6f,0.6f,1.0f,0.0f);
if (input.Bary.w > 1.0) //color the tips of the triangle
{
shade = min(min(saturate((1.0f - input.Bary.x) * 10.0f),saturate((1.0f - input.Bary.y) * 10.0f)),saturate((1.0f - input.Bary.z) * 10.0f));
}
else if(input.Bary.w > 0.0) //color two edges of the triangle
{
shade = min(saturate(input.Bary.x * 10.0f),saturate(input.Bary.z * 10.0f));
////do possible river depiction
//float rivTexCoord;
//if(input.Bary.x < input.RivSize)
//{
// if(input.RivClockwise == 1.0f)
// rivTexCoord = 1.0 - input.RivTexCoord; //clockwise
// else
// rivTexCoord = input.RivTexCoord; //counter-clockwise
// shade = gradTex.Sample(samLinear,rivTexCoord + time);
// rivColor = rivColor * shade;
// rivColor.a = 1.0f;
//}
}
float4 FinalColor;
float4 grey = float4(shade, shade, shade, 1.0f);
FinalColor = color * grey;
return FinalColor;
}