Xedi.Xermawan's Blog

personal-technical blog

[3] on directx 11 : load 3D model from file

leave a comment »

di project sebelumnya saya hanya menggambar 3d kubus. sangat menarik jika program bisa me-load model 3D yang dibuat oleh 3D editor. format paling populer untuk coba-coba tentu adalah wavefront obj ūüôā . File .obj ini hanya bisa untuk static 3d model, tidak mendukung animasi. Dan biasanya ada 1 file pasangan tambahan untuk setiap .obj yaitu .mtl. ¬†File .mtl dimaksudkan untuk menyimpan material ( konstanta pencahayaan , seperti diffuse, spekular ) . namun .mtl file ini optional. File .obj sebenarnya adalah text file. terdapat 2 kata disini “3D model” & “text file”, dan pasti yang terbayang adalah parsing yang lamaaaa . dan memang iya. parsingnya lama. untuk mengakali ini , .obj diubah ke .vbo ( ada orang yang sudah buat tool converter .obj to .vbo . .vbo apa itu?, .vbo sebenarnya adalah versi binary dari .obj, sehingga tidak perlu ada proses parsing waktu load object. 1 fungsi tambahan LoadModel_VBO, dan saya mengubah informasi vertex menjadi :
DirectX::XMFLOAT3 position;
DirectX::XMFLOAT3 normal;
DirectX::XMFLOAT2 texcoord;

fungsi load VBO :

	void LoadModel_VBO( unsigned char* meshData, ID3D11Buffer** vertexBuffer,ID3D11Buffer** indexBuffer,int& vertexCount,int& indexCount)  {
		// The first 4 bytes of the BasicMesh format define the number of vertices in the mesh.
		int numVertices = *reinterpret_cast<int*>(meshData);

		// The following 4 bytes define the number of indices in the mesh.
		int numIndices = *reinterpret_cast<int*>(meshData + sizeof(int));

		// The next segment of the BasicMesh format contains the vertices of the mesh.
		vertex_type* vertices = reinterpret_cast<vertex_type*>(meshData + sizeof(int) * 2);

		// The last segment of the BasicMesh format contains the indices of the mesh.
		unsigned short* indices = reinterpret_cast<unsigned short*>(meshData + sizeof(int) * 2 + sizeof(vertex_type) * numVertices);

		// Create the vertex and index buffers with the mesh data.

		D3D11_SUBRESOURCE_DATA vertexBufferData = {0};
		vertexBufferData.pSysMem = vertices;
		vertexBufferData.SysMemPitch = 0;
		vertexBufferData.SysMemSlicePitch = 0;
		CD3D11_BUFFER_DESC vertexBufferDesc(numVertices * sizeof(vertex_type), D3D11_BIND_VERTEX_BUFFER);
		HRESULT hr = m_Device->CreateBuffer(
				&vertexBufferDesc,
				&vertexBufferData,
				vertexBuffer
				);
		assert( hr==S_OK );

		D3D11_SUBRESOURCE_DATA indexBufferData = {0};
		indexBufferData.pSysMem = indices;
		indexBufferData.SysMemPitch = 0;
		indexBufferData.SysMemSlicePitch = 0;
		CD3D11_BUFFER_DESC indexBufferDesc(numIndices * sizeof(unsigned short), D3D11_BIND_INDEX_BUFFER);
			m_Device->CreateBuffer(
				&indexBufferDesc,
				&indexBufferData,
				indexBuffer
				);
		assert( hr==S_OK );
		vertexCount = numVertices;
		indexCount = numIndices;
	}

output program ( saya me-load utah teapot –yang terkenal itu ¬†) :

teapot

full source code & project ( vs 2012 desktop ) . ( xedi_on_directx11___3___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/

// edi ermawan// yogyakarta , 30122013

Written by XediXermawan

December 30, 2013 at 7:01 pm

Posted in C/C++ Diary, DirectX

Tagged with ,

[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