<< Click to Display Table of Contents >> Navigation: Simplygon 7.1 examples > DXExample.cpp |
///////////////////////////////////////////////////////////////////////////
//
// System: Simplygon
// File: DXExample.cpp
// Language: C++
//
// Copyright (c) 2015 Donya Labs AB. All rights reserved.
//
// This is private property, and it is illegal to copy or distribute in
// any form, without written authorization by the copyright owner(s).
//
///////////////////////////////////////////////////////////////////////////
//
// #Description#
//
// A simple DirectX9 example which loads an OBJ-file,
// converts it to DirectX format (from right-handed to left-handed
// coordinate system) and reduces the Simplygon mesh.
// Both converted and reduced models are then displayed in a direct x window.
//
// Note that manual linking to local dx9 libs is required for the example to run.
//
///////////////////////////////////////////////////////////////////////////
// include the basic windows header files and the Direct3D header file
#include <windows.h>
#include <windowsx.h>
#include "../Common/Example.h"
#include <d3d9.h>
#include <d3dx9.h>
#include "Mesh.h"
#include <winerror.h>
// Define the screen resolution and start points
#define WINDOW_WIDTH 1000
#define WINDOW_HEIGHT 1000
#define WINDOW_START_X 150
#define WINDOW_START_Y 150
D3DVERTEXELEMENT9 dwDecl3[] =
{
{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
{0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
{0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
{0, 36, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0},
{0, 48, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BINORMAL, 0},
D3DDECL_END()
};
// Interface and device pointer
LPDIRECT3D9 D3D9Interface; // Pointer to D3D interface
LPDIRECT3DDEVICE9 D3D9Device; // Pointer to D3D device
// Mesh to be loaded and rendered
Mesh* original_d3d_mesh = NULL;
Mesh* lod_d3d_mesh = NULL;
//Simplygon geometry containers
spGeometryData original_simplygon_mesh = NULL;
spMaterialTable original_simplygon_materials = NULL;
ID3DXEffect* Shader = NULL; // D3DX effect interface
bool ShowLOD = false;
bool visualize_debug = false;
// Camera settings
float OrbitRadius = 10.0f;
float OrbitRotation = 90.0f;
D3DXVECTOR3 OrbitCenter(0, 0, 0);
// Function prototypes
void InitializeD3D(HWND hWnd); // Initializes D3D
void DeInitializeD3D(void); // De-initializes D3D
void Render(void); // Render function
void RunProcessing( bool use_remeshing ); //Runs remeshing or reduction
bool LoadOBJ(const std::string& import_path, spGeometryData geom); //Reads an OBJ and its material from a file path and stores them as spGeometryData and spMaterialTable
bool InitializeGraphics(void); // Initialize graphics
HWND InitializeWindow( HINSTANCE hInstance, int nCmdShow ); // Initialize window
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); // Callback function
bool CreateD3DMeshFromPackedGeometry(spPackedGeometryData PerVtxGeometry, Mesh * mesh); // Simplygon geometry to dxGeometry
bool SetMaterials(spPackedGeometryData PerVtxGeometry, spMaterialTable MaterialTable, Mesh * mesh); // Simplygon material to dxMaterial
// Desc: the main function
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
// Initialize Simplygon SDK
InitExample();
// Sets the tangent space type. DirectX uses a left-handed coordinate system.
sg->SetGlobalSetting( "DefaultTBNType" , SG_TANGENTSPACEMETHOD_ORTHONORMAL_LEFTHANDED);
// Initialize window
HWND hWnd = InitializeWindow(hInstance, nCmdShow);
// Initialize Direct3D
InitializeD3D(hWnd);
// Initialize graphics, quit if initialization fails
if(!InitializeGraphics())
return -1;
// Run a processing
bool use_remeshing = false; // if false, do a mesh lod instead
RunProcessing(use_remeshing);
// Main loop
MSG msg;
while(TRUE)
{
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if(msg.message == WM_QUIT)
{
break;
}
else if(msg.message == WM_LBUTTONUP)
{
ShowLOD = false;
}
else if(msg.message == WM_LBUTTONDOWN)
{
ShowLOD = true;
}
else if(msg.message == WM_RBUTTONUP)
{
visualize_debug = false;
}
else if(msg.message == WM_RBUTTONDOWN)
{
visualize_debug = true;
}
// Render a frame
Render();
}
// Deinitialize D3D
DeInitializeD3D();
delete original_d3d_mesh;
delete lod_d3d_mesh;
// Deinitialize Simplygon SDK
original_simplygon_materials = NULL;
original_simplygon_mesh = NULL;
DeinitExample();
return 0;
}
//Reads an OBJ and its material from a file path
//and stores them as spGeometryData and spMaterialTable
bool LoadOBJ(const std::string& import_path, spGeometryData geom)
{
spWavefrontImporter importer = sg->CreateWavefrontImporter();
importer->SetImportFilePath( import_path.c_str() );
if(!importer->RunImport())
{
MessageBox(NULL, "No geometry loaded!", "FAILED", 0);
return false;
}
spGeometryData combined_geometry = importer->GetScene()->GetCombinedGeometry();
geom->DeepCopy(combined_geometry, true);
original_simplygon_materials = importer->GetScene()->GetMaterialTable();
if(original_simplygon_materials.IsNull())
{
MessageBox(NULL, "Material assignment failed!", "FAILED", 0);
return false;
}
return true;
}
//Run a processing of the geometry
//If the use_remeshing flag is true, it performs a remeshing,
//otherwise a regular reduction
//The processed mesh is converted back to a
void RunProcessing( bool use_remeshing )
{
std::string exePath = GetExecutablePath();
std::string output_filename = exePath + "object.obj";
std::string output_material_filename = exePath + "object.mtl";
std::string output_diffuse_filename = exePath + "object_diffuse.png";
std::string output_normals_filename = exePath + "object_normals.png";
// Make a copy of the geometry, we need the original for texture casting later.
// The remesher will replace the data of the geometry after it has processed it.
spGeometryData reduction_geometry = original_simplygon_mesh->NewCopy(true);
// Create a Scene-object and a SceneMesh-object.
// Place the reduction_geometry into the SceneMesh,
// and then the SceneMesh as a child to the RootNode.
spScene scene = sg->CreateScene();
spSceneMesh mesh = sg->CreateSceneMesh();
mesh->SetGeometry( reduction_geometry );
mesh->SetName( reduction_geometry->GetName()->GetText() );
scene->GetRootNode()->AddChild( mesh );
spReductionProcessor red;
spMappingImage mapping_image;
if(use_remeshing)
{
// Remesh it
spRemeshingProcessor remesher = sg->CreateRemeshingProcessor();
// set settings
remesher->GetRemeshingSettings()->SetOnScreenSize( 400 );
remesher->GetMappingImageSettings()->SetGenerateMappingImage( true );
remesher->GetMappingImageSettings()->SetWidth(512);
remesher->GetMappingImageSettings()->SetHeight(512);
remesher->GetMappingImageSettings()->SetTexCoordLevel(0);
remesher->SetScene(scene);
remesher->GetRemeshingSettings()->SetHardEdgeAngleInRadians(60.0);
// run it
remesher->RemeshGeometry();
// Mapping image is needed later on for texture casting.
mapping_image = remesher->GetMappingImage();
}
else
{
// Reduce it
red = sg->CreateReductionProcessor();
// set settings
red->GetReductionSettings()->SetTriangleRatio( 0.7f );
red->GetNormalCalculationSettings()->SetReplaceNormals(true);
red->GetNormalCalculationSettings()->SetHardEdgeAngleInRadians(180.0);
red->GetMappingImageSettings()->SetGenerateMappingImage( true );
red->GetMappingImageSettings()->SetWidth(1024);
red->GetMappingImageSettings()->SetHeight(1024);
red->GetMappingImageSettings()->SetUseFullRetexturing(true);
red->GetMappingImageSettings()->SetTexCoordLevel(0);
red->GetReductionSettings()->SetDataCreationPreferences(SG_DATACREATIONPREFERENCES_PREFER_ORIGINAL_DATA);
red->SetScene(scene);
// run it
red->RunProcessing();
// Mapping image is needed later on for texture casting.
mapping_image = red->GetMappingImage();
}
//Extract the processed scene mesh
spSceneMesh topmesh = SimplygonSDK::Cast<ISceneMesh>(scene->GetRootNode()->GetChild(0));
// Cast diffuse texture and normal map data into a new material
// Create new material table.
spMaterialTable output_materials = sg->CreateMaterialTable();
// Create new material for the table.
spMaterial output_material = sg->CreateMaterial();
output_materials->AddMaterial( output_material );
// Cast diffuse texture data
// Cast the data using a color caster
spColorCaster color_caster = sg->CreateColorCaster();
color_caster->SetColorType( SG_MATERIAL_CHANNEL_DIFFUSE );
color_caster->SetSourceMaterials( original_simplygon_materials );
color_caster->SetMappingImage( mapping_image ); // The mapping image we got from the remeshing process.
color_caster->SetOutputChannels( 3 ); // RGB, 3 channels! (1 would be for gray scale, and 4 would be for RGBA.)
color_caster->SetOutputChannelBitDepth( 8 ); // 8 bits per channel. So in this case we will have 24bit colors RGB.
color_caster->SetDilation( 10 ); // To avoid mip-map artifacts, the empty pixels on the map needs to be filled to a degree as well.
color_caster->SetOutputFilePath( output_diffuse_filename.c_str() ); // Where the texture map will be saved to file.
color_caster->CastMaterials(); // Fetch!
color_caster->SetIsSRGB(true);
// set the material properties
// Set the diffuse multiplier for the texture. 1 means it will not differ from original texture,
// For example: 0 would ignore a specified color and 2 would make a color twice as pronounced as the others.
output_material->SetDiffuseRed(1);
output_material->SetDiffuseGreen(1);
output_material->SetDiffuseBlue(1);
// Set material to point to created texture filename.
output_material->SetTexture( SG_MATERIAL_CHANNEL_DIFFUSE , output_diffuse_filename.c_str() );
// cast normal map texture data
// cast the data using a color caster
spNormalCaster normal_caster = sg->CreateNormalCaster();
normal_caster->SetSourceMaterials( original_simplygon_materials );
normal_caster->SetGenerateTangentSpaceNormals( true );
normal_caster->SetMappingImage( mapping_image );
normal_caster->SetOutputChannels( 3 ); // RGB, 3 channels! (But really the x, y and z values for the normal)
normal_caster->SetOutputChannelBitDepth( 8 );
normal_caster->SetDilation( 10 );
normal_caster->SetOutputFilePath( output_normals_filename.c_str() );
normal_caster->CastMaterials();
// Set material to point to created texture filename.
output_material->SetTexture( SG_MATERIAL_CHANNEL_NORMALS , output_normals_filename.c_str() );
// Create a packed, left-handed version of the simplygon LOD for rendering
spGeometryData leftHandedGeom = topmesh->GetGeometry()->NewCopy(true);
leftHandedGeom->ConvertHandedness();
spPackedGeometryData packed_geom = leftHandedGeom->NewPackedCopy();
// fetch various data to be able to set up a new dxmesh
D3DVERTEXELEMENT9 decl[MAXD3DDECLLENGTH];
const DWORD options = original_d3d_mesh->GetD3D9Mesh()->GetOptions();
const DWORD triCount = packed_geom->GetTriangleCount();
const DWORD vertCount = packed_geom->GetVertexCount();
// fetch vertex declaration
HRESULT hr = original_d3d_mesh->GetD3D9Mesh()->GetDeclaration( decl );
if(FAILED(hr))
{
return;
}
// if lod dxmesh exists, delete
if(lod_d3d_mesh)
{
delete lod_d3d_mesh;
}
// create a new dxmesh
lod_d3d_mesh = new Mesh();
bool result = lod_d3d_mesh->Create(triCount, vertCount, options, decl, D3D9Device);
if(!result)
{
return;
}
// copy simplygon data to dxmesh
result = CreateD3DMeshFromPackedGeometry(packed_geom, lod_d3d_mesh);
if(!result)
{
return;
}
// copy simplygon material data to dxmesh
result = SetMaterials(packed_geom, output_materials, lod_d3d_mesh);
if(!result)
{
return;
}
}
// Message handler
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
break;
}
return DefWindowProc (hWnd, message, wParam, lParam);
}
// Initializes D3D
void InitializeD3D(HWND hWnd)
{
D3D9Interface = Direct3DCreate9(D3D_SDK_VERSION); // Create the D3D9 Interface
D3DPRESENT_PARAMETERS D3D9PresentParameters; // Create D3D9 parameter struct
ZeroMemory(&D3D9PresentParameters, sizeof(D3D9PresentParameters)); // Zero out the memory
D3D9PresentParameters.Windowed = TRUE; // Run window in windowed mode
D3D9PresentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
D3D9PresentParameters.hDeviceWindow = hWnd;
D3D9PresentParameters.BackBufferFormat = D3DFMT_X8R8G8B8;
D3D9PresentParameters.BackBufferWidth = WINDOW_WIDTH;
D3D9PresentParameters.BackBufferHeight = WINDOW_HEIGHT;
D3D9PresentParameters.EnableAutoDepthStencil = TRUE; // Automatically use the z-buffer
D3D9PresentParameters.AutoDepthStencilFormat = D3DFMT_D16; // 16-bit pixel format for z-buffer
D3D9PresentParameters.FullScreen_RefreshRateInHz = 0; // Default refresh rate
D3D9PresentParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; // Vertical sync
DWORD backBufferQualityLevels = 0;
DWORD depthStencilQualityLevels = 0;
D3DMULTISAMPLE_TYPE msaaType = D3DMULTISAMPLE_4_SAMPLES;
// try to enable 4x msaa
HRESULT hr = D3D9Interface->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3D9PresentParameters.BackBufferFormat,
D3D9PresentParameters.Windowed, msaaType, &backBufferQualityLevels);
if (SUCCEEDED(hr))
{
hr = D3D9Interface->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL, D3D9PresentParameters.AutoDepthStencilFormat, D3D9PresentParameters.Windowed, msaaType,
&depthStencilQualityLevels);
if (SUCCEEDED(hr))
{
if (backBufferQualityLevels == depthStencilQualityLevels)
{
if (backBufferQualityLevels > 0)
{
D3D9PresentParameters.MultiSampleQuality = backBufferQualityLevels - 1;
D3D9PresentParameters.MultiSampleType = msaaType;
}
else
{
D3D9PresentParameters.MultiSampleQuality = backBufferQualityLevels;
D3D9PresentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
}
}
}
}
// Initialize the D3D9 Device
hr = D3D9Interface->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_HARDWARE_VERTEXPROCESSING, &D3D9PresentParameters, &D3D9Device);
if(FAILED(hr))
{
return;
}
D3DCAPS9 caps;
DWORD MaxAnisotrophy = 1;
// Set max anisotrophy value
if (!(D3D9Device->GetDeviceCaps(&caps)))
{
if (caps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY)
{
MaxAnisotrophy = caps.MaxAnisotropy;
}
else
{
MaxAnisotrophy = 1;
}
}
}
// Renders the frame
void Render(void)
{
// Clear window to gray (also clear depth buffer)
D3D9Device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(10, 10, 10), 1.0f, 0);
D3D9Device->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
// Ready scene for rendering
D3D9Device->BeginScene();
D3DXMATRIX matRotateY;
OrbitRotation += 0.003f; // Increase rotation for each frame
D3DXMatrixRotationY(&matRotateY, OrbitRotation);
D3DXMATRIX matView; // The view transform matrix
D3DXMatrixLookAtLH(&matView,
&D3DXVECTOR3 (0, OrbitRadius/2.0f, OrbitRadius*1.45f), // The camera position
&D3DXVECTOR3 (OrbitCenter), // The look-at position
&D3DXVECTOR3 (0.0f, 1.0f, 0.0f)); // The up direction
D3DXMATRIX matProjection; // The projection transform matrix
D3DXMatrixPerspectiveFovLH(&matProjection,
D3DXToRadian(35), // The horizontal field of view
(FLOAT)WINDOW_WIDTH / (FLOAT)WINDOW_HEIGHT, // Aspect ratio
1.0f, // The near view-plane
OrbitRadius*3); // The far view-plane
D3DXMATRIX worldMatrix = matRotateY * matView;
D3DXMATRIX finalMatrix = worldMatrix * matProjection;
bool UseShader = true;
// if shader, enable effects
if(UseShader)
{
// send parameters to the shader
Shader->SetTechnique("TransformTechnique");
D3DXMATRIX m;
Shader->SetMatrix("World", &worldMatrix);
Shader->SetMatrix("WorldViewProj", &finalMatrix);
Shader->SetVector("gLightDir", &D3DXVECTOR4(1.0f, 1.0f, 0.0f, 1.0));
Shader->SetBool("visualize_debug", visualize_debug); //Render only normal map shading
// Apply the technique contained in the effect
UINT NumberOfPasses;
Shader->Begin( &NumberOfPasses, 0 );
uint p = 0 ;
for( UINT p = 0; p < NumberOfPasses; ++p )
{
// Render dx mesh
if(original_d3d_mesh && !ShowLOD)
{
Shader->BeginPass( p );
LPDIRECT3DTEXTURE9* DiffuseList = original_d3d_mesh->GetD3D9DiffuseTextures();
LPDIRECT3DTEXTURE9 DiffuseTex = DiffuseList[0];
Shader->SetTexture("gDiffuseTexture", DiffuseTex);
LPDIRECT3DTEXTURE9* NormalsList = original_d3d_mesh->GetD3D9NormalsTextures();
LPDIRECT3DTEXTURE9 NormalsTex = NormalsList[0];
Shader->SetTexture("NormalMap", NormalsTex);
original_d3d_mesh->Render(D3D9Device);
Shader->EndPass();
}
else if(lod_d3d_mesh && ShowLOD)
{
Shader->BeginPass( p );
LPDIRECT3DTEXTURE9* DiffuseList = lod_d3d_mesh->GetD3D9DiffuseTextures();
LPDIRECT3DTEXTURE9 DiffuseTex = DiffuseList[0];
Shader->SetTexture("gDiffuseTexture", DiffuseTex);
LPDIRECT3DTEXTURE9* NormalsList = lod_d3d_mesh->GetD3D9NormalsTextures();
LPDIRECT3DTEXTURE9 NormalsTex = NormalsList[0];
Shader->SetTexture("NormalMap", NormalsTex);
lod_d3d_mesh->Render(D3D9Device);
Shader->EndPass();
}
Shader->EndPass();
}
Shader->End();
}
// Finish scene
D3D9Device->EndScene();
// Render the scene on screen
D3D9Device->Present(NULL, NULL, NULL, NULL);
}
// Desc: cleans up Direct3D
void DeInitializeD3D(void)
{
D3D9Device->Release(); // Release device
D3D9Interface->Release(); // Release interface
}
// Desc: initializes the graphics (mesh)
bool InitializeGraphics(void)
{
std::string ImportGeometryPath = GetAssetPath() + "simplygonman.obj";
std::string ImportShaderPath = GetAssetPath() + "shader.fx";
//Load .obj to simplygon
if(original_simplygon_mesh != NULL)
original_simplygon_mesh->Release();
//Load an OBJ from
original_simplygon_mesh = sg->CreateGeometryData();
if(!LoadOBJ(ImportGeometryPath, original_simplygon_mesh))
return false;
//Calculate D3D tangent space for original geometry
spTangentCalculator tangentspacecalc = sg->CreateTangentCalculator();
tangentspacecalc->SetTexCoordsSetId(0);
tangentspacecalc->CalculateTangents(original_simplygon_mesh);
//Create a packed, left-handed version of the right-handed simplygon geometry to use for DX rendering
spGeometryData leftHandedOriginalGeom = original_simplygon_mesh->NewCopy(true);
leftHandedOriginalGeom->ConvertHandedness();
spPackedGeometryData packed_geom = leftHandedOriginalGeom->NewPackedCopy();
const DWORD triCount = packed_geom->GetTriangleCount();
const DWORD vertCount = packed_geom->GetVertexCount();
//Create D3D mesh from simplygon geometry
original_d3d_mesh = new Mesh();
bool result = original_d3d_mesh->Create(triCount, vertCount, 0, dwDecl3, D3D9Device);
if(!result)
{
return false;
}
CreateD3DMeshFromPackedGeometry(packed_geom, original_d3d_mesh);
// copy simplygon material data to dxmesh
result = SetMaterials(packed_geom, original_simplygon_materials, original_d3d_mesh);
if(!result)
{
return false;
}
// Load a texture/normal map shader
LPD3DXBUFFER pBufferErrors = NULL;
HRESULT hr = D3DXCreateEffectFromFile( D3D9Device, ImportShaderPath.c_str(), NULL, NULL, 0, NULL, &Shader, &pBufferErrors );
if( FAILED(hr) )
{
LPVOID pCompilErrors = pBufferErrors->GetBufferPointer();
MessageBox(NULL, (const char*)pCompilErrors, "Effect Compile Error",
MB_OK|MB_ICONEXCLAMATION);
}
original_simplygon_mesh->CalculateExtents(false);
D3DXVECTOR3 AABBMin, AABBMax;
real inf[3];
real sup[3];
original_simplygon_mesh->GetInf(inf);
original_simplygon_mesh->GetSup(sup);
AABBMin = D3DXVECTOR3(inf);
AABBMax = D3DXVECTOR3(sup);
OrbitRadius = D3DXVec3Length(&(AABBMax-AABBMin));
OrbitCenter = AABBMin + ((AABBMax-AABBMin)/2.0f);
return true;
}
HWND InitializeWindow( HINSTANCE hInstance, int nCmdShow )
{
// Setup window class
HWND hWnd;
WNDCLASSEX wc;
// Zero out the memory
ZeroMemory(&wc, sizeof(WNDCLASSEX));
// Fill window class with information
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = "WindowClass";
// Register window class
RegisterClassEx(&wc);
// Create the window
hWnd = CreateWindowEx(NULL, "WindowClass", "DirectX9 Processing example [press LMB to view LOD model. Press RMB to view only shading.]",
WS_OVERLAPPEDWINDOW, WINDOW_START_X, WINDOW_START_Y, WINDOW_WIDTH, WINDOW_HEIGHT,
NULL, NULL, hInstance, NULL);
// Make the window visible
ShowWindow(hWnd, nCmdShow);
return hWnd;
}
bool CreateD3DMeshFromPackedGeometry(spPackedGeometryData PerVtxGeometry, Mesh * mesh)
{
LPD3DXMESH D3D9Mesh = mesh->GetD3D9Mesh();
LPDIRECT3DVERTEXBUFFER9 VertexBuffer = NULL;
LPDIRECT3DINDEXBUFFER9 IndexBuffer = NULL;
// Get vertex buffer
HRESULT hResult = D3D9Mesh->GetVertexBuffer(&VertexBuffer);
if( FAILED( hResult ) )
{
return false;
}
// Get index buffer
hResult = D3D9Mesh->GetIndexBuffer(&IndexBuffer);
if( FAILED( hResult ) )
{
return false;
}
uint NumberOfVertices = PerVtxGeometry->GetVertexCount();
uint NumberOfFaces = PerVtxGeometry->GetTriangleCount();
spRidArray VertexIDs = PerVtxGeometry->GetVertexIds();
spRealArray Coords = PerVtxGeometry->GetCoords();
spRealArray Normals = PerVtxGeometry->GetNormals();
spRealArray TexCoords = PerVtxGeometry->GetTexCoords(0);
spRealArray BiTangents;
spRealArray Tangents;
if( PerVtxGeometry->GetTangents(0) )
Tangents = PerVtxGeometry->GetTangents(0);
if( PerVtxGeometry->GetBitangents(0) )
BiTangents = PerVtxGeometry->GetBitangents(0);
// Get the original declaration of the mesh (as when created)
std::vector<D3DVERTEXELEMENT9> vecDeclaration(MAX_FVF_DECL_SIZE);
hResult = D3D9Mesh->GetDeclaration( &*vecDeclaration.begin() );
if( FAILED( hResult ) )
{
return false;
}
void* VertexBufferPointer = NULL;
// Get a writable handle to vertex buffer
hResult = VertexBuffer->Lock(0, sizeof(VertexBuffer), (void**)&VertexBufferPointer, 0 );
if(FAILED( hResult ) )
{
return false;
}
// Get vertex size
DWORD BytesPerVertex = D3D9Mesh->GetNumBytesPerVertex();
// Copy data from simplygon geometry to d3d geometry
for(uint i = 0; i < NumberOfVertices; ++i)
{
char *vertex_start = &(((char*)VertexBufferPointer)[i*BytesPerVertex]);
spRealData normals_xyz = sg->CreateRealData();
spRealData tangents_xyz = sg->CreateRealData();
spRealData bitangents_xyz = sg->CreateRealData();
Normals->GetTuple(i, normals_xyz);
Tangents->GetTuple(i, tangents_xyz);
BiTangents->GetTuple(i, bitangents_xyz);
uint atDeclaration = 0;
for(uint j = 0; j < vecDeclaration.size(); ++j)
{
// Vertices
if(vecDeclaration[j].Type == D3DDECLTYPE_FLOAT3 && vecDeclaration[j].Usage == D3DDECLUSAGE_POSITION)
{
// get simplygon data
spRealData xyz = sg->CreateRealData();
Coords->GetTuple(i, xyz);
// set data to dxMesh
float *dxyz = (float*) &(vertex_start[vecDeclaration[j].Offset]);
dxyz[0] = xyz[0];
dxyz[1] = xyz[1];
dxyz[2] = xyz[2];
}
// Normals
if(vecDeclaration[j].Type == D3DDECLTYPE_FLOAT3 && vecDeclaration[j].Usage == D3DDECLUSAGE_NORMAL)
{
spRealData xyz = sg->CreateRealData();
Normals->GetTuple(i, xyz);
float *dxyz = (float*) &(vertex_start[vecDeclaration[j].Offset]);
dxyz[0] = xyz[0];
dxyz[1] = xyz[1];
dxyz[2] = xyz[2];
}
// Texcoords
if(vecDeclaration[j].Type == D3DDECLTYPE_FLOAT2 && vecDeclaration[j].Usage == D3DDECLUSAGE_TEXCOORD)
{
spRealData uv = sg->CreateRealData();
TexCoords->GetTuple(i, uv);
float *duv = (float*) &(vertex_start[vecDeclaration[j].Offset]);
duv[0] = uv[0];
duv[1] = uv[1];
}
// Bitangents
if(vecDeclaration[j].Type == D3DDECLTYPE_FLOAT3 && vecDeclaration[j].Usage == D3DDECLUSAGE_BINORMAL)
{
spRealData xyz = sg->CreateRealData();
if(BiTangents)
{
BiTangents->GetTuple(i, xyz);
float *duv = (float*) &(vertex_start[vecDeclaration[j].Offset]);
duv[0] = xyz[0];
duv[1] = xyz[1];
duv[2] = xyz[2];
}
}
// Tangents
if(vecDeclaration[j].Type == D3DDECLTYPE_FLOAT3 && vecDeclaration[j].Usage == D3DDECLUSAGE_TANGENT)
{
spRealData xyz = sg->CreateRealData();
if(Tangents)
{
Tangents->GetTuple(i, xyz);
float *duv = (float*) &(vertex_start[vecDeclaration[j].Offset]);
duv[0] = xyz[0];
duv[1] = xyz[1];
duv[2] = xyz[2];
}
}
// End of field, break
if(vecDeclaration[j].Type == D3DDECLTYPE_UNUSED)
{
break;
}
}
}
// Unlock the vertex buffer
VertexBuffer->Unlock();
VertexBuffer->Release();
// Fetch index buffer information
D3DINDEXBUFFER_DESC IndexBufferDescription;
if( FAILED(IndexBuffer->GetDesc( &IndexBufferDescription ) ))
{
return false;
}
// Set the index size (16 or 32 bits) to be able to traverse the index buffer
int IndexSize;
if(IndexBufferDescription.Format == D3DFMT_INDEX32)
{
IndexSize = 4;
}
else
{
IndexSize = 2;
}
BYTE* IndexBufferPointer = NULL;
// Lock buffer to access index buffer
if(FAILED(IndexBuffer->Lock(0, sizeof(IndexBuffer), (void**)&IndexBufferPointer, 0) ) )
{
return false;
}
// Copy index data
DWORD CurrentTri[3] = {0,0,0};
for(uint i = 0; i < NumberOfFaces*3; i+=3 )
{
CurrentTri[0] = VertexIDs->GetItem(i+0);
CurrentTri[1] = VertexIDs->GetItem(i+1);
CurrentTri[2] = VertexIDs->GetItem(i+2);
for( uint e=0; e<3; ++e )
{
memcpy(IndexBufferPointer, &CurrentTri[e], IndexSize);
IndexBufferPointer += IndexSize;
}
}
// Unlock the index buffer
IndexBuffer->Unlock();
IndexBuffer->Release();
real inf[3], sup[3];
PerVtxGeometry->GetInf(inf);
PerVtxGeometry->GetSup(sup);
float dist = inf[2] - sup[2];
dist = dist > inf[1] - sup[1] ? dist : inf[1] - sup[1];
dist = dist > inf[0] - sup[0] ? dist : inf[0] - sup[0];
return true;
}
bool SetMaterials(spPackedGeometryData PerVtxGeometry, spMaterialTable MaterialTable, Mesh * mesh)
{
LPD3DXMESH D3D9Mesh = mesh->GetD3D9Mesh();
uint NumberOfFaces = PerVtxGeometry->GetTriangleCount();
// Lock attribute buffer
DWORD* AttributeBufferPointer = NULL;
HRESULT hResult = D3D9Mesh->LockAttributeBuffer(0, &AttributeBufferPointer);
if(FAILED(hResult))
{
return false;
}
// Copy over material ids (Proxy Lods only have one material)
for(uint a = 0; a < NumberOfFaces; ++a)
{
AttributeBufferPointer[a] = 0;
}
// Unlock attribute buffer
hResult = D3D9Mesh->UnlockAttributeBuffer();
if(FAILED(hResult))
{
return false;
}
// Setup materials
uint NumberOfMaterials = MaterialTable->GetMaterialsCount();
mesh->SetNumMaterials(NumberOfMaterials);
for(uint i = 0; i < NumberOfMaterials; ++i)
{
// get simplygon material
spMaterial m = Cast<IMaterial>(MaterialTable->GetItem(i));
// get diffuse and normal map
std::string dpath = m->GetLayeredTexture(SG_MATERIAL_CHANNEL_DIFFUSE, 0)->GetText();
std::string npath = m->GetLayeredTexture(SG_MATERIAL_CHANNEL_NORMALS, 0)->GetText();
D3DMATERIAL9 mat;
// Set the RGBA for diffuse reflection.
mat.Diffuse.r = m->GetColorRed (SG_MATERIAL_CHANNEL_DIFFUSE);
mat.Diffuse.g = m->GetColorGreen(SG_MATERIAL_CHANNEL_DIFFUSE);
mat.Diffuse.b = m->GetColorBlue (SG_MATERIAL_CHANNEL_DIFFUSE);
mat.Diffuse.a = m->GetColorAlpha(SG_MATERIAL_CHANNEL_DIFFUSE);
// store material and texture paths
bool result = mesh->CreateTexture(D3D9Device, i, dpath, npath, mat);
if(!result)
{
// material creation failed
MessageBox(NULL, "material creation failed!", "FAILED", 0);
return false;
}
}
return true;
}