Xedi.Xermawan's Blog

personal-technical blog

[2] on directx 11 : sending data to shader

leave a comment »

Bagaimana mengirim data dari code CPU ( c++ code ) ke code GPU ( hlsl ) ?. Di program sebelumnya, beberapa data yang di kirim ke shader :

  • vertex dan index , direpresentasikan dengan D3D11Buffer , di set ke shader dengan IASetVertexBuffers, dan IASetIndexBuffers. prefix IA : buffer ini di set ke input assembler stage dan dapat diakses di VS .
  • model, view, projection matrix,  direpresentasikan dengan D3D11Buffer, di set ke shader dengan VSSetConstantBuffers. prefix VS,karena buffer ini akan dipakai sebagai global variable di vertex shader .
  • texture, berupa shader resource view, di set ke shader dengan PSSetShaderResources. prefix PS, texture hanya dipakai di pixel shader stage.

model, view projection matrik dibuat dengan bind flag D3D11_BIND_CONSTANT_BUFFER . mvp disini nilainya tidak konstant, tapi berubah-ubah per-frame. lalu kenapa bind flag nya ‘constant buffer’?, hal ini yang membuat saya bertanya diawal2. “constant buffer” disini, dimaksudkan nilainya tetap konstant per 1 proses draw command. namun di draw command selanjutnya bisa berubah. Jika kita ingin memiliki variable yang “semacam” mvp matrix ( berubah-ubah per-frame, dan dapat diakses di shader –vs,ps) , maka kita harus membuat constant buffer semacam ini. sebagai percobaan yang bisa dilihat hasilnya langsung, saya ingin mengirim data ke pixel shader untuk mengubah saturation-desaturation dari texture kubus di program sebelumnya. di c++ code saya perlu struct untuk meng-hold data ini :

struct color_constantbuffer
{
DirectX::XMFLOAT4 saturation;
DirectX::XMFLOAT4 luminance;
};

sedangkan di pixel shader, saya perlu membuat constant buffer, dengan kata kunci cbuffer :

cbuffer ColorConstantBuffer
{
float4 saturation;
float4 luminance;
};

next step, perlu dibuat d3dbuffer untuk menyimpan data : ( m_ColorConstantBuffer  adalah ID3D11Buffer* )

D3D11_BUFFER_DESC ColorConstBufferDesc;
ColorConstBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
ColorConstBufferDesc.ByteWidth = sizeof(color_constantbuffer);
ColorConstBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
ColorConstBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
ColorConstBufferDesc.MiscFlags = 0;
ColorConstBufferDesc.StructureByteStride = 0;

hr = m_Device->CreateBuffer( &ColorConstBufferDesc , NULL , &m_ColorConstantBuffer );

dan untuk memberi tahu gpu, kalau buffer ini akan dipakai di pixel shader stage , perlu di set dengan command :

m_DevContext->PSSetConstantBuffers( 0,1,&m_ColorConstantBuffer);

lalu bagaimana cara meng-update color constant buffer ini ?.Untuk mvp constant buffer dipakai UpdateSubresource. Cara lain adalah menggunakan fungsi Map/Unmap . Bedanya dengan UpdateSubresource, Map/Unamp, bisa read-write data ke gpu, sedangkan UpdateSubresource hanya write saja. meng-update color constant buffer dengan Map/Unmap :

D3D11_MAPPED_SUBRESOURCE mappedResource;
color_constantbuffer* colvalue;
HRESULT hr = m_DevContext->Map(m_ColorConstantBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
assert( hr == S_OK );
// get ptr data
colvalue = (color_constantbuffer*)mappedResource.pData;
// set data
colvalue->luminance = DirectX::XMFLOAT4( );  //  <— set new value here
colvalue->saturation = DirectX::XMFLOAT4( );  //  <— set new value here
// Unlock the constant buffer.
m_DevContext->Unmap(m_ColorConstantBuffer, 0);

di pixel shader, variabel luminance&saturation dipakai menghitung saturaion/desaturation.  ( Simple_PS_02.hlsl )

float4 main(PixelShaderInput input) : SV_TARGET
{
// PixelShaderInput.color input doesn’t used in this shader
float4 texColorOut;
// Sample the pixel color from the texture using the sampler at this texture coordinate location.
texColorOut = shaderTexture.Sample(SampleType, input.tex);
float3 luminanceVal = dot( texColorOut, float3(luminance.x,luminance.y,luminance.z));
float4 finalCol = float4( lerp( luminanceVal , texColorOut, saturation ),1.0f);
finalCol.z = texColorOut.z;
return finalCol;
}

note : rumus menghitung saturation/desaturation , nemu di SINI

agar lebih interaktif,  di percobaan ini saya menambahkan input untuk user melalui keyboard yang memungkinkan user mengubah saturation dan luminance.

tombol 1-4 : saturation

tombol 5-8: luminance

hasil akhir program percobaan ini: menggambar kubus, dimana warna texture bisa diubah-ubah warnanya dengan mengubah saturation. input lain :

u-i : pitch

o-p: roll

k-l : yaw

n-m : zoom in/out

screenshoot output program (klik gambar untuk memperbesar *) :

cube_rot_frog

full source code & project ( vs 2012 desktop ) . ( xedi_on_directx11___2___from___N.vcxproj )

svn checkout : https://xedi-on-directx-11.googlecode.com/svn/trunk

project home : http://code.google.com/p/xedi-on-directx-11/

// edie // nganjuk  , 27122013

Written by XediXermawan

December 27, 2013 at 4:50 pm

Posted in C/C++ Diary, DirectX

Tagged with ,

[1] on directx 11 : texturing

leave a comment »

Di program sebelumnya informasi gambar/ vertex data di-representasikan dengan data struct dibawah ini :  (vertex_type.hpp)

struct vertex_type
{
DirectX::XMFLOAT3 position;
DirectX::XMFLOAT3 color;
};

struct ini ber-asosiasi dengan shader code : ( Simple_VS.hlsl )

struct VertexShaderInput
{
float3 pos : POSITION;
float3 color : COLOR0;
};

dengan sedikit modifikasi, kita bisa menambahkan texture ke vertex data untuk kubus :

vertex_type.hpp

Simple_VS.hlsl

Simple_PS.hlsl

structvertex_type{DirectX::XMFLOAT3 position;DirectX::XMFLOAT3 color;DirectX::XMFLOAT2 texcoord; // ← added

};

struct VertexShaderInput{float3 pos : POSITION;float3 color : COLOR0;float2 tex : TEXCOORD0;// ← added

};

 

struct PixelShaderInput{float4 pos : SV_POSITION;float3 color : COLOR0;float2 tex:TEXCOORD0;//← added

};

Karena informasi vertex berubah, data vertex juga harus diubah,  program sekarang harus mengirim : position (float3), color(float3), dan texture coordinate(float2) ke GPU .position adalah jelas koordinat x,y,z di space 3d, color adalah r,g,b di sini, sedangkan texture coordinate, bisa dijelaskan dengan gambar sebagai berikut :

coord_textured

koordinat front face cube :
{XMFLOAT3(-1.0f, -1.0f, -1.0f),XMFLOAT3(0.0f, 0.0f, 0.0f), XMFLOAT2(0.0f, 1.0f)},
{XMFLOAT3(-1.0f, 1.0f, -1.0f),XMFLOAT3(0.0f, 0.0f, 1.0f), XMFLOAT2(0.0f, 0.0f)},
{XMFLOAT3( 1.0f, 1.0f, -1.0f),XMFLOAT3(1.0f, 0.0f, 0.0f), XMFLOAT2(1.0f, 0.0f)},
{XMFLOAT3( 1.0f, -1.0f, -1.0f),XMFLOAT3(0.0f, 0.0f, 1.0f), XMFLOAT2(1.0f, 1.0f)},
dari gambar, texture akan menutup triangle di koordinat yang bersesuaian.
Langkah selanjutnya adalah mengubah input layout, untuk memberi tahu GPU kalau aplikasi akan mengirim layout data seperti ini :

 D3D11_INPUT_ELEMENT_DESC inputVertexDesc[3]; // position , color, texture coord
 inputVertexDesc[0].SemanticName = "POSITION";
 inputVertexDesc[0].SemanticIndex = 0;
 inputVertexDesc[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
 inputVertexDesc[0].InputSlot = 0;
 inputVertexDesc[0].AlignedByteOffset = 0;
 inputVertexDesc[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
 inputVertexDesc[0].InstanceDataStepRate = 0;

inputVertexDesc[1].SemanticName = "COLOR";
 inputVertexDesc[1].SemanticIndex = 0;
 inputVertexDesc[1].Format = DXGI_FORMAT_R32G32B32_FLOAT;
 inputVertexDesc[1].InputSlot = 0;
 inputVertexDesc[1].AlignedByteOffset = 12; //D3D11_APPEND_ALIGNED_ELEMENT;
 inputVertexDesc[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
 inputVertexDesc[1].InstanceDataStepRate = 0;

inputVertexDesc[2].SemanticName = "TEXCOORD";  // added
 inputVertexDesc[2].SemanticIndex = 0;
 inputVertexDesc[2].Format = DXGI_FORMAT_R32G32B32_FLOAT;
 inputVertexDesc[2].InputSlot = 0;
 inputVertexDesc[2].AlignedByteOffset =24; //D3D11_APPEND_ALIGNED_ELEMENT;
 inputVertexDesc[2].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
 inputVertexDesc[2].InstanceDataStepRate = 0;
 int numElement = sizeof( inputVertexDesc ) / sizeof ( inputVertexDesc[0] );
 hr = m_Device->CreateInputLayout
 ( inputVertexDesc, numElement , vs_ba , vs_ba_len , &m_InputLayout );

step selanjutnya kita perlu menyiapkan data texture. Di project saya menambahkan DDSTextureLoader class ( class helper untuk me-load texture dari file ).

CreateDDSTextureFromFile( m_Device , L”../data/textures/texture_01.DDS”, nullptr, &m_TextureShaderResView, MAXSIZE_T);

dan data texture ini kita kirim ke gpu sebelum eksekusi gambar terjadi :

m_DevContext->PSSetShaderResources(0, 1, &m_TextureShaderResView);
m_DevContext->DrawIndexed(36, 0, 0);

Hasil eksekusi program :

cube_rot_textured

full source code & project ( vs 2012 desktop ) . ( xedi_on_directx11___1___from___N.vcxproj )

svn checkout : https://xedi-on-directx-11.googlecode.com/svn/trunk

project home : http://code.google.com/p/xedi-on-directx-11/

// edie // nganjuk , 26122013

Written by XediXermawan

December 26, 2013 at 4:44 pm

Posted in C/C++ Diary, DirectX

Tagged with , ,

Auto beautifying C++ code

leave a comment »

Disini saya ingin share simple script untuk “mempercantik” c++ code disuatu folder project dan melakukan svn commit setelah itu. jadi semacam selalu ada auto corrector jika kamu menulis code yang tidak sesuai aturan ( bahkan mungkin aturan yang kamu buat sendiri) .

code yang rapih diharapkan memiliki sedikit bugs dan juga ingat programmer menulis code tidak hanya untuk mesin, tetapi juga untuk dibaca manusia yang lain. untung nya untuk masalah indentation & formating ada software keren & free untuk melakukan ini, yaitu AStyle (  http://astyle.sourceforge.net/ )  .  dengan batch script dibawah ini, semuanya terjadi otomatis :


@echo off
SET ASTYLE_DIR="N:\test\AStyle\bin"
SET SRC_ROOT_DIR="N:\test\test_astyle\source01"
echo ..AStyle beautfying...
%ASTYLE_DIR%\AStyle.exe --style=google --indent=spaces=4 -xn -xc -xl -xk -xe -n --align-pointer=type --recursive %SRC_ROOT_DIR%\*.h %SRC_ROOT_DIR%\*.cpp %SRC_ROOT_DIR%\*.hpp %SRC_ROOT_DIR%\*.c
echo ..done..
echo ..SVN Comitting..
svn commit %SRC_ROOT_DIR% --message "auto commit: Astyle auto beautify code "
echo ..done..

SET ASTYLE_DIR         : dir dari astyle exe

SET SRC_ROOT_DIR  : root dir source code

dengan menambahkan ini scheduler task / script semuanya berjalan otomatis .

// edie  // surabaya 23-12-2013

Written by XediXermawan

December 23, 2013 at 9:40 am

problem solved : wordpress remove code indentation

leave a comment »

so you wanna post fancy cool blog post in wordpress and it’s time to copy-paste your code to wordpress editor. and …, all indentation from your code editor lost !!. this is really not good, right ?. I search some soluton to fix this and I have one :

-copy & paste your code to http://hilite.me/ on “Source Code” edit box part.

-click “Highlight” button

-a result code will be generated in “Preview” edit box. copy-paste code from there to WordPress editor

-indentation back!

huzzah  , thanks to http://hilite.me/

 

// edie  surabaya 22-12-2013

Written by XediXermawan

December 22, 2013 at 5:24 pm

Posted in Uncategorized

Tagged with

[0] on directx 11 : hello cube

with 4 comments

dulu saya mengalami banyak kesulitan ketika memulai belajar directx 11 (mid 2012). saya ga nemu tutorial yang benar-benar directx 11, kebanyakan bercampur dengan directx 9 / 10 dimana beberapa fungsi sudah deprecated(hilang/diganti), tidak build-able dengan compiler VS terbaru yang saya pakai(MSVC 2012). walaupun secara garis besar/filosofi tidak jauh berbeda, tapi itu tentu tidak bagus untuk pemula 🙂 . untuk itu saya tertarik untuk membuat dokumentasi ini . belajar graphics API secara memang bukan hal mudah, karena kita berusaha memahami apa yang orang buat —yaitu graphics API, yang kalau diartikan :  komplek API untuk mentransfer sesuatu yang ingin kita gambar ke hardware. salah satu cara untuk menghadapi kompleksitas ini adalah menggunakan graphics debugger ( PIX, Nvidia Nsight, dll.) . Namun saya meragukan seorang pemula mengetahui hal ini & mau menggunakannya diawal2 belajar (source : me ) . Untuk menegaskan apa yang saya katakan di 3 baris terakhir, coba lihat tweet dari John Carmack dibawah ini :Image

:-d . walaupun begitu, belajar tentang graphics itu sangat menarik dan fun. Kita menulis codes dan kita bisa melihat hasilnya dilayar . (sesuatu yang setara dengan ini -> membuat rangkaian elektronik , dan melihat LED berjalan, hehe ) .Di negara kita memang sangat jarang orang membutuhkan skill tentang Directx/OpenGL, kalau orang ingin membuat game, game engine adalah pilihan yang bijak jika orientasinya produktivitas , daripada menulis code graphics dari awal. Namun, pengetahuan dasar tentang bagaimana sesuatu itu digambar dilayar, sangat perlu. Misalnya, game dikembangkan dengan game engine (Unreal (UDK), Unity, dll. ), dan ingin membuat efek khusus, pasti akhirnya perlu menulis custom shader. CMIIW , soalnya belum pernah pakai engine2 ini.  oke, itulah beberapa motivasi 🙂 . Saya ingin memulai dengan beberapa istilah.

Beberapa istilah dalam DirectX yang perlu diketahui :

device : API/interface/class/whatever yang digunakan untuk membuat resource (textures, shaders, etc). dan juga digunakan untuk mendeteksi h/w sekarang support directx versi berapa. instance dari device ini bisa dibuat sendiri ( windows desktop app/ windows store app/ wp8 native app ) atau sudah disediakan (misalnya : wp8 xaml-native type app ) .

device context : API/interface/class/whatever yang digunakan untuk menggambar/ mengirim resources/ draw command ke gpu. device context menyimpan kumpulan setting/keadaan dari gambar yang akan kita gambar. suatu kalimat di sinetron “kamu ngomong begitu konteksnya apa” mungkin bisa sedikit memiliki arti yang sama dengan “device context” disini .:p

resources : sumberdaya dari apa yang akan digambar dilayar: shaders, textures, buffers (vertex, index )

rendering pipeline : dalam bahasa indonesia, pipeline : pipa saluran . dimana draw command/resource di proses disini sampai akhirnya muncul dilayar > http://msdn.microsoft.com/en-us/library/windows/desktop/ff476882(v=vs.85).aspx

bind : istilah yang digunakan untuk meng-attach resource ke gpu .

texture : gambar.

shader program : atau cuma disebut shader. program yang mirip C, untuk mengolah vertex & pixel .shader ini di compile menjadi byte code yang akhirnya nanti dikirim ke gpu, sebelum draw command dieksekusi. cara compilenya bisa dengan fxc.exe ( bawaan directx sdk ) dan menggunakan hasil byte code nya di runtime, atau bisa dengan D3DCompileFromFile (input text file, compile dilakukan saat runtime) . namun D3DCompileFromFile hanya bisa dipakai untuk debugging saja.

dan sepertinya masih banyak lagi :d

Hello World Program.

saya  disini membuat program untuk menggambar cube (kubus) , yang cukup untuk mewakili bagaimana sebuah proses menggambar ke gpu terjadi. programnya dibuat sesederhana mungkin , sehingga lebih fokus ke bagian graphics. Main program structure :

Game.Init()

while( true )     { // main loop

Game.OnInput() -- event

Game.Update()

Game.Render()

}

Game.ShutDown()

Game adalah nama class yang saya gunakan untuk men-wrap main program


#pragma once

#include "stdafx.h"
#include "vertextypes.hpp"

using namespace DirectX;

extern unsigned char* GetByteArrayFromFile(std::string filename,unsigned int& length);

class XGame {
private:
	unsigned int m_ScreenWidth;
	unsigned int m_ScreenHeight;
	HWND* m_HWindow;
	// d3d variable
	ID3D11Device* m_Device;
	ID3D11DeviceContext* m_DevContext;
	IDXGISwapChain* m_SwapChain;
	ID3D11RenderTargetView* m_RenderTarget;
	// draw variable
	ID3D11Buffer* m_VertexBuffer;
	ID3D11Buffer* m_IndexBuffer;
	ID3D11Buffer* m_ConstantBuffer;
	ID3D11VertexShader* m_VertexShader;
	ID3D11PixelShader* m_PixelShader;
	ID3D11InputLayout* m_InputLayout;
	unsigned long m_VertexCount;
	unsigned long m_IndexCount;
	double m_TotalTime;
	mvp_constantbuffer m_ConstantBufferData;
public :
	XGame() {
	}
	~XGame() {
	}

	void Initialize(HWND& hwindow, unsigned int sheight, unsigned int swidth) {
		// ----- #step01 ----- create device & swap-chain
		m_HWindow = &hwindow;
		m_ScreenWidth  = swidth;
		m_ScreenHeight = sheight;

		D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_10_0 };
		// create swapchain & device
		DXGI_SWAP_CHAIN_DESC swapChainDesc;
		swapChainDesc.BufferDesc.Width  = (UINT) m_ScreenWidth;
		swapChainDesc.BufferDesc.Height = (UINT) m_ScreenHeight;
		swapChainDesc.BufferDesc.RefreshRate.Numerator = 0;
		swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
		swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
		swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
		// swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_CENTERED;
		swapChainDesc.SampleDesc.Count = 1;
		swapChainDesc.SampleDesc.Quality = 0;
		swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
		swapChainDesc.BufferCount = 2;
		swapChainDesc.OutputWindow = (*m_HWindow);
		swapChainDesc.Windowed = TRUE;
		swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
		swapChainDesc.Flags = 0;

		HRESULT hr = D3D11CreateDeviceAndSwapChain(
		                 NULL,
		                 D3D_DRIVER_TYPE_HARDWARE, // original : D3D_DRIVER_TYPE_HARDWARE, D3D_DRIVER_TYPE_WARP
		                 NULL,
		                 D3D11_CREATE_DEVICE_SINGLETHREADED,
		                 featureLevels,
		                 _countof(featureLevels),
		                 D3D11_SDK_VERSION,
		                 &swapChainDesc,
		                 &m_SwapChain,
		                 &m_Device,
		                 NULL,
		                 &m_DevContext);
		assert(SUCCEEDED(hr));

		// ----- #step02 ----- setting render target
		// Get swap chain's back buffer, create its render target view and set that view as render target
		ID3D11Texture2D* backbuffer;
		hr = m_SwapChain->GetBuffer(0, __uuidof(*backbuffer), (void**)&backbuffer);
		assert(SUCCEEDED(hr));

		hr = m_Device->CreateRenderTargetView(backbuffer, NULL, &m_RenderTarget);
		assert(SUCCEEDED(hr));

		m_DevContext->OMSetRenderTargets(1, &m_RenderTarget, NULL);

		// ----- #step03 ----- setting view port
		// Set viewport
		D3D11_VIEWPORT viewport;
		viewport.TopLeftX = 0;
		viewport.TopLeftY = 0;
		viewport.Width  = (FLOAT) m_ScreenWidth;
		viewport.Height = (FLOAT) m_ScreenHeight;
		viewport.MinDepth = 0.f;
		viewport.MaxDepth = 1.f;
		m_DevContext->RSSetViewports(1, &viewport);

		// ----- #step04 ----- set raster state
		D3D11_RASTERIZER_DESC rasterizerState;
		rasterizerState.CullMode = D3D11_CULL_FRONT;// D3D11_CULL_NONE;D3D11_CULL_FRONT;D3D11_CULL_BACK
		rasterizerState.FillMode = D3D11_FILL_SOLID; // D3D11_FILL_SOLID ;//D3D11_FILL_WIREFRAME;
		rasterizerState.FrontCounterClockwise = FALSE;
		rasterizerState.DepthBias = false;
		rasterizerState.DepthBiasClamp = 0;
		rasterizerState.SlopeScaledDepthBias = 0;
		rasterizerState.DepthClipEnable = true;
		rasterizerState.ScissorEnable = false;
		rasterizerState.MultisampleEnable = false;
		rasterizerState.AntialiasedLineEnable = true;
		ID3D11RasterizerState* pRS;
		m_Device->CreateRasterizerState( &rasterizerState, &pRS );
		m_DevContext->RSSetState(pRS);

		PreparingDraw();
	}

	void PreparingDraw() {
		// ----- #step05 ----- preparing vertex data & index to buffers
		vertex_type cubeVertices[] = {
		    // Front Face
			{XMFLOAT3(-1.0f, -1.0f, -1.0f),XMFLOAT3(0.0f, 0.0f, 0.0f) },
			{XMFLOAT3(-1.0f,  1.0f, -1.0f),XMFLOAT3(0.0f, 0.0f, 1.0f) },
			{XMFLOAT3( 1.0f,  1.0f, -1.0f),XMFLOAT3(1.0f, 0.0f, 0.0f) },
			{XMFLOAT3( 1.0f, -1.0f, -1.0f),XMFLOAT3(0.0f, 0.0f, 1.0f) },

			// Back Face
			{XMFLOAT3(-1.0f, -1.0f, 1.0f),XMFLOAT3(1.0f, 0.0f, 1.0f) },
			{XMFLOAT3( 1.0f, -1.0f, 1.0f),XMFLOAT3(0.0f, 1.0f, 1.0f) },
			{XMFLOAT3( 1.0f,  1.0f, 1.0f),XMFLOAT3(1.0f, 0.0f, 0.0f) },
			{XMFLOAT3(-1.0f,  1.0f, 1.0f),XMFLOAT3(1.0f, 1.0f, 1.0f) },

			// Top Face
			{XMFLOAT3(-1.0f, 1.0f, -1.0f),XMFLOAT3(0.0f, 1.0f, 1.0f) },
			{XMFLOAT3(-1.0f, 1.0f,  1.0f),XMFLOAT3(1.0f, 0.0f, 0.0f) },
			{XMFLOAT3( 1.0f, 1.0f,  1.0f),XMFLOAT3(1.0f, 1.0f, 0.0f) },
			{XMFLOAT3( 1.0f, 1.0f, -1.0f),XMFLOAT3(1.0f, 0.0f, 1.0f) },

			// Bottom Face
			{XMFLOAT3(-1.0f, -1.0f, -1.0f),XMFLOAT3(1.0f, 0.0f, 0.0f) },
			{XMFLOAT3( 1.0f, -1.0f, -1.0f),XMFLOAT3(1.0f, 0.0f, 0.0f) },
			{XMFLOAT3( 1.0f, -1.0f,  1.0f),XMFLOAT3(1.0f, 0.0f, 0.0f) },
			{XMFLOAT3(-1.0f, -1.0f,  1.0f),XMFLOAT3(1.0f, 0.0f, 0.0f) },

			// Left Face
			{XMFLOAT3(-1.0f, -1.0f,  1.0f),XMFLOAT3(1.0f, 0.0f, 0.0f) },
			{XMFLOAT3(-1.0f,  1.0f,  1.0f),XMFLOAT3(0.0f, 1.0f, 1.0f) },
			{XMFLOAT3(-1.0f,  1.0f, -1.0f),XMFLOAT3(1.0f, 0.0f, 0.0f) },
			{XMFLOAT3(-1.0f, -1.0f, -1.0f),XMFLOAT3(1.0f, 0.0f, 0.0f) },

			// Right Face
			{XMFLOAT3( 1.0f, -1.0f, -1.0f),XMFLOAT3(1.0f, 0.0f, 1.0f) },
			{XMFLOAT3( 1.0f,  1.0f, -1.0f),XMFLOAT3(0.0f, 1.0f, 1.0f) },
			{XMFLOAT3( 1.0f,  1.0f,  1.0f),XMFLOAT3(0.0f, 1.0f, 0.0f) },
			{XMFLOAT3( 1.0f, -1.0f,  1.0f),XMFLOAT3(1.0f, 0.0f, 1.0f) },
		};

		unsigned short cubeIndices[] = {
			// Front Face
			0,  1,  2,
			0,  2,  3,

			// Back Face
			4,  5,  6,
			4,  6,  7,

			// Top Face
			8,  9, 10,
			8, 10, 11,

			// Bottom Face
			12, 13, 14,
			12, 14, 15,

			// Left Face
			16, 17, 18,
			16, 18, 19,

			// Right Face
			20, 21, 22,
			20, 22, 23
		};
		m_IndexCount = ARRAYSIZE(cubeIndices);

		CD3D11_BUFFER_DESC verticesBufferDesc (sizeof(cubeVertices), D3D11_BIND_VERTEX_BUFFER);
		D3D11_SUBRESOURCE_DATA vertexSubResData;
		vertexSubResData.pSysMem     = cubeVertices;
		vertexSubResData.SysMemPitch = 0;
		vertexSubResData.SysMemSlicePitch = 0;

		HRESULT hr = m_Device->CreateBuffer( &verticesBufferDesc, &vertexSubResData, &m_VertexBuffer );
		assert( hr == S_OK );

		// indices
		CD3D11_BUFFER_DESC indicesBufferDesc(sizeof(cubeIndices), D3D11_BIND_INDEX_BUFFER);
		D3D11_SUBRESOURCE_DATA indexSubResData;
		indexSubResData.pSysMem = cubeIndices;
		indexSubResData.SysMemPitch = 0;
		indexSubResData.SysMemSlicePitch = 0;

		hr = m_Device->CreateBuffer( &indicesBufferDesc, &indexSubResData, &m_IndexBuffer);
		assert( hr == S_OK );

		// ----- #step06 ----- create shaders
		unsigned int vs_ba_len=0;
		unsigned char* vs_ba = GetByteArrayFromFile("simple_vs.cso",vs_ba_len);
		assert( vs_ba != NULL );

		unsigned int ps_ba_len=0;
		unsigned char* ps_ba = GetByteArrayFromFile("simple_ps.cso",ps_ba_len);
		assert( ps_ba != NULL );

		hr = m_Device->CreateVertexShader( vs_ba, vs_ba_len, NULL, &m_VertexShader );
		assert( hr == S_OK);

		hr = m_Device->CreatePixelShader( ps_ba, ps_ba_len, NULL, &m_PixelShader );
		assert( hr == S_OK);

		// ----- #step07 ----- create input layout
		D3D11_INPUT_ELEMENT_DESC inputVertexDesc[2]; // position , color

		inputVertexDesc[0].SemanticName = "POSITION";
		inputVertexDesc[0].SemanticIndex = 0;
		inputVertexDesc[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
		inputVertexDesc[0].InputSlot = 0;
		inputVertexDesc[0].AlignedByteOffset = 0;
		inputVertexDesc[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
		inputVertexDesc[0].InstanceDataStepRate = 0;

		inputVertexDesc[1].SemanticName = "COLOR";
		inputVertexDesc[1].SemanticIndex = 0;
		inputVertexDesc[1].Format = DXGI_FORMAT_R32G32B32_FLOAT;
		inputVertexDesc[1].InputSlot = 0;
		inputVertexDesc[1].AlignedByteOffset =12;//D3D11_APPEND_ALIGNED_ELEMENT;
		inputVertexDesc[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
		inputVertexDesc[1].InstanceDataStepRate = 0;

		int numElement = sizeof( inputVertexDesc ) / sizeof ( inputVertexDesc[0] );

		hr = m_Device->CreateInputLayout( inputVertexDesc, numElement , vs_ba , vs_ba_len , &m_InputLayout );
		assert( hr == S_OK );

		delete[] vs_ba;
		delete[] ps_ba;

		// ----- #step08 ----- create constant buffer
		D3D11_BUFFER_DESC constBufferDesc;

		constBufferDesc.Usage     = D3D11_USAGE_DEFAULT;
		constBufferDesc.ByteWidth = sizeof(mvp_constantbuffer);
		constBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
		constBufferDesc.CPUAccessFlags = 0;
		constBufferDesc.MiscFlags      = 0;
		constBufferDesc.StructureByteStride = 0;

		hr = m_Device->CreateBuffer( &constBufferDesc , NULL , &m_ConstantBuffer );
		assert( hr == S_OK );

		// ----- #step09 ----- projection matrix
		float aspectRatio = 800.0f / 480.0f;
		float fovAngleY = 100.0f * XM_PI / 180.0f;
		if (aspectRatio < 1.0f) {
			fovAngleY /= aspectRatio;
		}

		XMStoreFloat4x4(&m_ConstantBufferData.projection,
		                XMMatrixTranspose(
		                    XMMatrixPerspectiveFovRH(
		                        fovAngleY,
		                        aspectRatio,
		                        0.01f,
		                        100.0f
		                    )
		                )
		               );
	}
	void Update(const double delta_time) {
		// ----- #step10 : game update here
		XMVECTOR eye = XMVectorSet(0.0f, 0.0f, 3.5f, 0.0f);
		XMVECTOR at  = XMVectorSet(0.0f, -0.1f, 0.0f, 0.0f);
		XMVECTOR up  = XMVectorSet(0.0f, 0.1f, 0.0f, 0.0f);

		m_TotalTime = m_TotalTime + delta_time;
		XMStoreFloat4x4(&m_ConstantBufferData.view, XMMatrixTranspose(XMMatrixLookAtRH(eye, at, up)));
		XMStoreFloat4x4(&m_ConstantBufferData.model, XMMatrixTranspose(XMMatrixRotationY(m_TotalTime)));
		if(m_TotalTime > 360)
			m_TotalTime =0;
	}
	void Render() {
		// ----- #step11 :  clear screen
		const float bg_color[] =  {0.1f, 0.1f, 0.1f, 1.0f};
		m_DevContext->ClearRenderTargetView(m_RenderTarget,bg_color);

		// ----- #step12 : set constant buffer
		m_DevContext->UpdateSubresource( m_ConstantBuffer,0,NULL,&m_ConstantBufferData,0,0);

		// ----- #step13 : set index & vertex buffer
		unsigned int stride, offset;
		stride = sizeof ( vertex_type );
		offset = 0;

		m_DevContext->IASetVertexBuffers( 0, 1 , &m_VertexBuffer , &stride, &offset );
		m_DevContext->IASetIndexBuffer( m_IndexBuffer , DXGI_FORMAT_R16_UINT, 0 );
		// ----- #step14 : set Primitive Topology
		m_DevContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST   ); // D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST

		// ----- #step15 : set shader, input layout, send draw
		m_DevContext->IASetInputLayout( m_InputLayout );
		m_DevContext->VSSetShader(m_VertexShader, NULL, 0);
		m_DevContext->VSSetConstantBuffers( 0,1,&m_ConstantBuffer);
		m_DevContext->PSSetShader(m_PixelShader, NULL, 0);
		m_DevContext->DrawIndexed(36, 0, 0);

		// ----- #step16 : swap buffer
		m_SwapChain->Present(1, 0);
	}
	void ShutDown() {
	}
	void OnSuspending() {
	}
	void OnResuming() {
	}
	void OnHandleInput() {
	}
};

beberapa steps yang saya comment di code diatas :

// —– #step01 —– create device & swap-chain
// —– #step02 —– setting render target
// —– #step03 —– setting view port
// —– #step04 —– set raster state
// —– #step05 —– preparing vertex data & index to buffers
// —– #step06 —– create shaders
// —– #step07 —– create input layout
// —– #step08 —– create constant buffer
// —– #step09 —– projection matrix
// —– #step10 —– game update here
// —– #step11 —– clear screen
// —– #step12 —– set constant buffer
// —– #step13 —– set index & vertex buffer
// —– #step14 —– set set Primitive Topology
// —– #step15 —– set shader, input layout, send draw
// —– #step16 —– swap buffer

Hasil dari program diatas : gambar kubus 3d yang berputar terhadap sumbu-y ( garis atas -bawah kalau kamu melihat layar )

cube_rotsaya post full source code & project ( vs 2012 desktop ) di

svn checkout : https://xedi-on-directx-11.googlecode.com/svn/trunk

project home : http://code.google.com/p/xedi-on-directx-11/

komentar, correction , pertanyaan , are welcome ! 🙂

// edi ermawan Surabaya, 22-12-2013

Written by XediXermawan

December 22, 2013 at 5:01 pm

Posted in C/C++ Diary, DirectX

File mana yang termodifikasi ?

leave a comment »

Misalnya saya memiliki 1000 file yang akan saya prosess oleh suatu program, dengan script saya bisa melakukannya seperti ini :

for i=0 to i=1000 { process file ke-i }      

jadi dengan klik sebuat script pekerjaan selesai. Namun, ada beberapa file dari 1000 file tersebut yang berubah / saya modifikasi lagi, sehingga saya perlu mengulang eksekusi script diatas lagi :

for i=0 to i=1000 { process file ke-i }      

Ini tentu tidak efisien dan lama, karena saya mengubah beberapa file, namun 1000 file masih diprocess lagi. Kode yang efisien seharusnya begini :

for i=0 to i=1000 { jika file ke-i ter-modifikasi, maka process file ke-i }    

untuk itu saya perlu suatu program untuk mengecek apakah file ke-i, termodifikasi / tidak. Pekerjaan semacam ini bisa mungkin saja dilakukan dengan python, lua, atau scripting language yang lain. Namun kali ini , (dan waktu2yg lain) , saya suka pakai c/c++ dengan kombinasi Batch , hehehe. Dan, program super simple itu sudah jadi, xediff.exe :d . berikut contoh efisien script yang saya maksud .

[ run_works.bat ]

@echo off
SET XDIFF=N:\XediProjects\Release\Xediff.exe
SET TARGETDIR=D:\test\test
for %%i in ( %TARGETDIR%\*.* ) do (
 call checkmodified.bat %%i
)
echo .. Done..

[ checkmodified.bat ]

@echo off
%XDIFF% %1 > temp.txt
set /p XDF= < temp.txt
 if "%XDF%"=="1" (
 @echo ..do something: this file changed %1 %XDF%
 )
del temp.txt

Terdapat 2 file batch, run_works.bat yang memanggil checkmodified.bat. Alasan kenapa jadi 2 file BAT adalah : pipe di BAT tidak bisa bekerja. { apa itu pipe? } . lalu apa yang dilakukan xediff.exe? : xediff.exe menerima argumen berupa file path , dan memberikan output (stdout) ‘1’ & ‘0’  ,file termodifikasi atau tidak . xediff.exe adalah program simple yang mengecek last written time dari suatu file . berikut kodenya [ this is ugly, but i like to share 🙂    ]

[xediff.exe]

// Xedi Xermawan <c> 2013
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#include <fstream>

using namespace std;

bool GetLastWriteTime(HANDLE hFile, SYSTEMTIME& lastaccess,TCHAR* fileLastAccess)	{
	bool isEqual = true;
    FILETIME ftCreate, ftAccess, ftWrite;
    SYSTEMTIME stUTC, stLocal;
    // Retrieve the file times for the file.
    if (!GetFileTime(hFile, &ftCreate, &ftAccess, &ftWrite))
        return false;
    // Convert the last-write time to local time.
    FileTimeToSystemTime(&ftWrite, &stUTC);
    SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);
	if(stLocal.wMonth != lastaccess.wMonth ||
	   stLocal.wDay!= lastaccess.wDay ||
	   stLocal.wYear!= lastaccess.wYear ||
       stLocal.wHour!= lastaccess.wHour ||
	   stLocal.wMinute!= lastaccess.wMinute ||
	   stLocal.wSecond!= lastaccess.wSecond
	   )
	{
		isEqual = false;
	}
	fstream fileOut(fileLastAccess,std::ios::out|std::ios::binary);
	const char* c=reinterpret_cast<const char*>(&stLocal);
	fileOut.write(c,sizeof(stLocal));
	fileOut.close();
	return isEqual;
}

bool GetLastTimeAccess(SYSTEMTIME& ret, TCHAR* fileLastAccess)  {
	fstream fileIn(fileLastAccess,std::ios::in | std::ios::binary);
	if(!fileIn) {
		return false;
	}
	fileIn.read( reinterpret_cast<char*>(&ret), sizeof(ret) );
	fileIn.close();
	return true;
}

void BreakPath(TCHAR* filepath, TCHAR* filedir, TCHAR* filename)	{
	unsigned int i=0,lastSlash=0;
	TCHAR buff[MAX_PATH];
	while(*filepath !='')	{
		buff[i] = *filepath;
		if(*filepath++=='\\')
			lastSlash=i;
		i++;
	}
	buff[i]='\0';
	i=0;
	while(i < lastSlash+1)	{
		*filedir++ = buff[i++];
	}
	*filedir++ ='.';
	*filedir++ ='x';
	*filedir++ ='d';
	*filedir++ ='f';
	*filedir++ ='\\';
	*filedir='';
	while(buff[i] !='')	{
		*filename++ = buff[i++];
	}
	*filename ='\0';
}

void FixPath(TCHAR* filedir, TCHAR* filename,TCHAR* filenamefix)	{
	while(*filedir !='')	{
		*filenamefix++ = *filedir++;
	}
	while(*filename !='')	{
		*filenamefix++ = *filename++;
	}
	*filenamefix++='.';
	*filenamefix++='x';
	*filenamefix++='d';
	*filenamefix++='i';
	*filenamefix++='f';
	*filenamefix++='f';
	*filenamefix='\0';
}

int _tmain(int argc, TCHAR *argv[])	 {
    HANDLE hFile;
	int retVal = 1;
    if( argc != 2 )	{
        retVal = 1;
		printf("%d",retVal);
		return retVal;
    }
	TCHAR* filepath = argv[1];
	TCHAR filedir[MAX_PATH];
	TCHAR filename[MAX_PATH];
	TCHAR filename_fix[MAX_PATH];
	SYSTEMTIME lastaccessnoted;
	BreakPath(filepath,filedir,filename);
	CreateDirectory( filedir , NULL );
	FixPath(filedir,filename,filename_fix);
	GetLastTimeAccess(lastaccessnoted, filename_fix );
    hFile = CreateFile(filepath, GENERIC_READ, FILE_SHARE_READ, NULL,OPEN_EXISTING, 0, NULL);

    if(hFile == INVALID_HANDLE_VALUE)	{
        retVal = 1;
		printf("%d",retVal);
		return retVal;;
    }
    if( (GetLastWriteTime( hFile, lastaccessnoted, filename_fix ) ))	 {
		retVal = 0;	// file same // not modified
		printf("%d",retVal);
		return retVal;;
	}
    CloseHandle(hFile);
	printf("%d",retVal);
	return retVal;
}

// edi ermawan // yogjakarta 27042013

// keywords: file modified  check, c++, c, Batch, incremental build

Written by XediXermawan

April 26, 2013 at 6:07 pm

Memperbanyak Assert

leave a comment »

Dalam pembuatan program, programmer sering kehilangan detail apa yang terjadi di bagian kode tertentu. Terutama kalau program yang dibuat terdiri dari ribuan baris kode.Lebih parah lagi, jika kode tersebut sudah lama tidak disentuh.  Dan ketika bug ditemukan , programmer akan mencari cara untuk memperbaiki bug tersebut dengan melakukan debugging ke kode yang diduga sebagai penyebab. Waktu penyelesaian tentu tergantung seberapa sulit bug tersebut. Usaha “mencari” solusi dengan debugging ini bisa di minimalkan jika kita memasang banyak ASSERT di kode. Contoh :
void DataSender::Init(std::string filename)    {
      std::ifstream config_file(filename, std::ios::in | std::ios::binary | std::ios::ate);
      assert( config_file.is_open() ) ;
      // do something
      // …
      // …
}
jika file config tidak bisa di buka, assertion failed akan terjadi , dan programmer/user akan segera tau. Skenario yang terjadi jika kode diatas tanpa ASSERT : suatu saat path file diubah, dan file tidak bisa dibuka. akibatnya akan ada masalah dengan class DataSender, jika berungtung program akan crash, dan programmer dapat crash/ stack trace, jika tidak kemungkinan DataSender akan tetap berjalan tapi data tidak terkirim. Programmer akan mencari dengan banyak dugaan penyebab: apa jaringan internet lagi down?, apa library networknya bermasalah?, apa pemakai class DataSender? apa terkirim tapi ada delay ?. banyak yang harus dijawab . arghhh.
dari contoh ini, assert bisa menghemat waktu :). assert akan dihilangkan di-release version , jika assert ingin dipakai di release version lebih baik memakai preprocessor untuk menggantikannya. disini ASSERT diganti dengan std::exception failed :p .

#ifdef NDEBUG // release
     #ifdef REAL_RELEASE
          #define MY_ASSERT(x)
     #else
          #define MY_ASSERT(x) if(!x) std::throw std::exception(“assertion failed”);
     #endif
#else          // debug
     #define MY_ASSERT(x) assert(x)
#endif

btw, hati-hati dengan kode semacam ini :

ASSERT( very_important_function() ) ;

🙂

Written by XediXermawan

April 14, 2013 at 6:54 pm

Posted in C/C++ Diary