source: GTP/trunk/App/Demos/Illum/PathMap/PathMapEffect.cpp @ 896

Revision 896, 55.4 KB checked in by szirmay, 18 years ago (diff)
Line 
1#include "dxstdafx.h"
2#include ".\pathmapeffect.h"
3#include "Material.hpp"
4#include "TexturedMaterial.h"
5#include "WoodMaterial.hpp"
6#include "TriangleMesh.h"
7#include "Transformed.h"
8#include "shlwapi.h"
9#include <queue>
10#include <fstream>
11
12#define TEST_CLUST 0
13//#define GENERATE_PATH_MAPS
14
15//! D3D vector-matrix multiplication
16D3DVECTOR operator *(const D3DVECTOR& v, const D3DMATRIX& m)
17{
18        D3DVECTOR r;
19        r.x = v.x * m._11 + v.y * m._21 + v.z * m._31 + m._41;
20        r.y = v.x * m._12 + v.y * m._22 + v.z * m._32 + m._42;
21        r.z = v.x * m._13 + v.y * m._23 + v.z * m._33 + m._43;
22        float h = v.x * m._14 + v.y * m._24 + v.z * m._34 + m._44;
23        if(h > 0.00001f || h < 0.00001f)
24        {
25                r.x /= h;
26                r.y /= h;
27                r.z /= h;
28        }
29        return r;
30}
31
32//! method name strings to be displayed on screen
33const wchar_t* PathMapEffect::Method::methodNames[10] =
34{
35        L"PRM",
36        L"PRM texture",
37        L"_",
38        L"_"
39        , NULL, NULL, NULL, NULL, NULL, NULL
40};
41
42//! method constants
43const PathMapEffect::Method PathMapEffect::Method::PRM(0);
44const PathMapEffect::Method PathMapEffect::Method::SHOWTEX(1);
45const PathMapEffect::Method PathMapEffect::Method::LAST(2);
46
47//! constructor
48PathMapEffect::PathMapEffect(LPDIRECT3DDEVICE9 device)
49:method(Method::PRM)
50{
51        rayId = 1;
52        this->device = device;
53
54        //first person camera allows more freedom of movement
55        camera = new CFirstPersonCamera();
56        lightCamera = new CFirstPersonCamera();
57
58        HRESULT hr;
59        DWORD effectCompileFlag=0;
60       
61        LPD3DXBUFFER compilationErrors;
62        if(FAILED(
63                hr =
64                        D3DXCreateEffectFromFile(
65                                device,
66                                L"pathMap.fx",
67                                NULL,
68                                NULL,
69                                0,
70                                NULL,
71                                &effect,
72                                &compilationErrors) )){
73                MessageBoxA( NULL, (LPSTR)compilationErrors->GetBufferPointer(), "Failed to load effect file!", MB_OK);
74                exit(-1);
75        }
76
77        //store buffers so we can reset them after rendering to texture render targets
78        device->GetRenderTarget(0, &frameColorBuffer);
79        device->GetDepthStencilSurface(&frameDepthStencilBuffer);
80       
81        //load empty texture
82        D3DXCreateTextureFromFile(device, L"media\\empty.bmp", &emptyTexture);
83
84        //set up a scene
85
86        //load hangar mesh
87        loadMesh( L"media\\fulltexchamber.x" );
88
89        //create hangar entity
90        Entity e1;
91        e1.owner = this;
92        e1.renderMesh = renderMeshes.at(0);
93        D3DXMatrixIdentity(&e1.modelWorldTransform);
94//      D3DXMatrixScaling(&e1.modelWorldTransform, 0.5f, 1.0f, 0.5f);
95        D3DXMatrixIdentity(&e1.inverseTransposedModelWorldTransform);
96//      D3DXMatrixScaling(&e1.inverseTransposedModelWorldTransform, 1.0f/0.5f, 1.0f, 1.0f/0.5f);
97
98        e1.createRayTraceEntity();
99       
100        entities.push_back(e1);
101
102
103        //load 'steps' mesh
104/*      loadMesh( L"media\\steps.x" );
105
106        //create step entities
107        //for(int eitor=0; eitor < 6; eitor++)
108        {
109                Entity e2;
110                e2.owner = this;
111                e2.renderMesh = renderMeshes.at(1);
112                D3DXMatrixTranslation(&e2.modelWorldTransform, 0.0f, -14.0f, 0.0f);
113                D3DXMatrixInverse(&e2.inverseTransposedModelWorldTransform, NULL, &e2.modelWorldTransform);
114                e2.createRayTraceEntity();
115                entities.push_back(e2);
116
117                D3DXMATRIX trasi, roti;
118                D3DXMatrixTranslation(&trasi, 7.0f, 14.0f, -7.0f);//7.25f, 13.5, -7.25); //rot 90 -90 90 trans 7.25 13.5 -7.25
119                D3DXMatrixRotationYawPitchRoll(&roti, -Vector::PI * 0.5, Vector::PI, 0.0);
120//              D3DXMatrixIdentity(&roti);
121                D3DXMatrixMultiply(&e2.modelWorldTransform, &roti, &trasi);
122                D3DXMatrixInverse(&e2.inverseTransposedModelWorldTransform, NULL, &e2.modelWorldTransform);
123                e2.createRayTraceEntity();
124                entities.push_back(e2);
125        }*/
126
127/*      for(int eitor=0; eitor < 6; eitor++)
128        {
129                Entity e2;
130                e2.owner = this;
131                e2.renderMesh = renderMeshes.at(1);
132                D3DXMatrixIdentity(&e2.modelWorldTransform);
133                D3DXMatrixScaling(&e2.modelWorldTransform, -0.5, 0.5, -0.5);
134                D3DXMATRIX trmx;
135                D3DXMatrixTranslation(&trmx, -8.0 + eitor * 2.8f, -3.2f, -8.6f + eitor * 0.6f);
136                e2.modelWorldTransform *= trmx;
137                D3DXMatrixIdentity(&e2.inverseTransposedModelWorldTransform);
138                D3DXMatrixScaling(&e2.inverseTransposedModelWorldTransform, -2.0, 2.0, -2.0);
139                D3DXMatrixTranslation(&trmx, +8.0 - eitor * 2.8f, 3.2f, 8.6f - eitor * 0.6f);
140                e2.inverseTransposedModelWorldTransform *= trmx;
141                e2.createRayTraceEntity();
142                entities.push_back(e2);
143        }*/
144
145        //compute the surface area of the complete geometry. useful for random sampling.
146        sumSurfaceArea = 0.0;
147        std::vector<PathMapEffect::Entity>::iterator entityIterator = entities.begin();
148        while(entityIterator != entities.end())
149        {
150                sumSurfaceArea += entityIterator->rayTraceEntity->getSurfaceArea();
151                entityIterator++;
152        }
153
154        //initialize camera
155        camera->SetViewParams( &D3DXVECTOR3(0.0f, 0.0f, 4.0f), &D3DXVECTOR3(0.0f, 0.0f, 0.0f));
156        D3DSURFACE_DESC fbdesc;
157        frameColorBuffer->GetDesc(&fbdesc);
158        camera->SetProjParams( D3DX_PI/2, (float)fbdesc.Width / fbdesc.Height, 0.1f, 300.0f );
159
160        //create resources for entities
161        createPRMTextures();
162
163        //set up spotlight
164        lightCamera->SetViewParams( &D3DXVECTOR3(5.0f, 0.0f, 0.0f), &D3DXVECTOR3(0.0f, 0.0f, 0.0f));
165        lightCamera->SetProjParams( D3DX_PI/1.9, 1.0f, 0.1f, 300.0f );
166
167        //create ray tracing kd-tree containg ray-traceable versions of entities
168        Intersectable** objs = new Intersectable*[entities.size()];
169        for(int u=0; u<entities.size(); u++)
170                objs[u] = entities.at(u).rayTraceEntity;
171        kdtree = new KDTree(objs, entities.size());
172        delete [] objs;
173
174        //create dummy render target texture for depth map rendering
175        device->CreateTexture(DEPTHMAPRES, DEPTHMAPRES, 1, D3DUSAGE_RENDERTARGET, D3DFMT_R32F, D3DPOOL_DEFAULT, &fakeTexture, NULL);
176        fakeTexture->GetSurfaceLevel(0, &fakeSurface);
177
178        //create a depthstencil texture for depth map rendering
179        device->CreateTexture(DEPTHMAPRES, DEPTHMAPRES, 1,
180                D3DUSAGE_DEPTHSTENCIL, D3DFMT_D24X8, D3DPOOL_DEFAULT, &depthMapTexture, NULL);
181        depthMapTexture->GetSurfaceLevel(0, &depthMapDepthStencilBuffer);
182
183        //create a stencil surface for PRM rendering (to avoid blend-adding to the same pixel for the same lightsource muliple times)
184        device->CreateDepthStencilSurface(128 * 32, 128 * NCLUSTERSPERENTITY / 32, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, 0, true, &prmBlendingDepthStencilBuffer, NULL);
185
186#ifdef GENERATE_PATH_MAPS
187        precompute();
188#else
189        loadPathMaps();
190#endif 
191
192        //create a texture for radion data (will be used for weight computations on the GPU)
193        device->CreateTexture(2 * NRADIONS / 4096, 4096, 1, 0, D3DFMT_A32B32G32R32F, D3DPOOL_DEFAULT, &radionTexture, NULL);
194        radionTexture->GetSurfaceLevel(0, &radionSurface);
195
196        //fill texture with data
197        uploadRadions();
198
199        //create weights render target
200        device->CreateTexture(4096, NRADIONS / 4096, 1, D3DUSAGE_RENDERTARGET, D3DFMT_R32F, D3DPOOL_DEFAULT, &weightsTexture, NULL);
201        weightsTexture->GetSurfaceLevel(0, &weightsSurface);
202
203        //create a sytem memory duplicate of the weights render target to be able to read back weights data
204        device->CreateTexture(4096, NRADIONS / 4096, 1, 0, D3DFMT_R32F, D3DPOOL_SYSTEMMEM, &sysMemWeightsTexture, NULL);
205        sysMemWeightsTexture->GetSurfaceLevel(0, &sysMemWeightsSurface);
206
207        //create a vertex buffer to be able to visualize entry radion positions
208        device->CreateVertexBuffer(NRADIONS * sizeof(float) * 6, D3DUSAGE_WRITEONLY, D3DFVF_XYZ | D3DFVF_NORMAL, D3DPOOL_DEFAULT,
209                &starterVertexBuffer, NULL);
210        void* pData;
211        starterVertexBuffer->Lock(0, 0, &pData, 0);
212        fillRadionPosArray(pData);
213        starterVertexBuffer->Unlock();
214
215#ifdef GENERATE_PATH_MAPS
216        savePathMaps();
217#endif
218}
219
220PathMapEffect::~PathMapEffect(void)
221{
222        //release all resources allocated in the constructor
223        starterVertexBuffer->Release();
224
225        depthMapTexture->Release();
226        depthMapDepthStencilBuffer->Release();
227        fakeTexture->Release();
228        fakeSurface->Release();
229
230        sysMemWeightsTexture->Release();
231        sysMemWeightsSurface->Release();
232        weightsTexture->Release();
233        weightsSurface->Release();
234        radionTexture->Release();
235        radionSurface->Release();
236
237        prmBlendingDepthStencilBuffer->Release();
238        delete kdtree;
239        emptyTexture->Release();
240        releaseTextures();
241        releaseMeshes();
242        releaseEntities();
243
244        frameColorBuffer->Release();
245        frameDepthStencilBuffer->Release();
246
247        effect->Release();
248        delete camera;
249        delete lightCamera;
250}
251
252void PathMapEffect::loadMesh(LPCWSTR fileName)
253{
254        RenderMesh*             renderMesh = new RenderMesh();
255
256        if(S_OK !=
257                D3DXLoadMeshFromX(      fileName,
258                                                        D3DXMESH_MANAGED,
259                            device,
260                                                        NULL,
261                                                        &renderMesh->materialBuffer,
262                                                        NULL,
263                                                        (DWORD*)&renderMesh->nSubsets,
264                                                        &renderMesh->mesh))
265        {
266                 MessageBox(NULL, fileName, L"Could not load mesh file!", MB_OK);
267                 return;
268        }
269        //convert mesh into a vertex format using a position, a normal and a texture register
270        //this is the only data our vertex shaders will require
271        renderMesh->setVertexFormat(D3DFVF_XYZ |
272                                                D3DFVF_NORMAL |
273                                                D3DFVF_TEX1, device);
274
275        //extract the D3DXMATERIAL* pointer from the generic D3DXBUFFER
276        renderMesh->materials = (D3DXMATERIAL*)renderMesh->materialBuffer->GetBufferPointer();
277
278        //for every material, load the specified texture
279        renderMesh->textures = new LPDIRECT3DTEXTURE9[renderMesh->nSubsets];
280        for(unsigned int i=0; i<renderMesh->nSubsets; i++)
281        {
282                wchar_t* wideTextureFileName = NULL;
283                if(renderMesh->materials[i].pTextureFilename)
284                {
285                        wideTextureFileName = new wchar_t[MultiByteToWideChar(CP_ACP, 0, renderMesh->materials[i].pTextureFilename, -1, NULL, 0)];
286                        MultiByteToWideChar(CP_ACP, 0, renderMesh->materials[i].pTextureFilename, -1, wideTextureFileName, 511);
287                }
288                renderMesh->textures[i] = loadTexture( wideTextureFileName );
289                if(wideTextureFileName)
290                        delete wideTextureFileName;
291        }
292
293        //lock the buffers and create ray tracing meshes from the data
294        LPDIRECT3DVERTEXBUFFER9 vertexBuffer;
295        renderMesh->mesh->GetVertexBuffer(&vertexBuffer);
296        D3DVERTEX* vertexData;
297        vertexBuffer->Lock(0,renderMesh->mesh->GetNumVertices()*renderMesh->mesh->GetNumBytesPerVertex(),(void**)&vertexData,0);
298        LPDIRECT3DINDEXBUFFER9 indexBuffer;
299        renderMesh->mesh->GetIndexBuffer(&indexBuffer);
300        unsigned short* indexData;
301        indexBuffer->Lock(0,renderMesh->mesh->GetNumFaces()*3*sizeof(unsigned short),(void**)&indexData,0);
302
303        //create a ray-tracing Material for the texture
304        if(renderMesh->textures[0])
305        {
306                D3DLOCKED_RECT lrect;
307                HRESULT hr = renderMesh->textures[0]->LockRect(0, &lrect, NULL, D3DLOCK_READONLY);
308                LPDIRECT3DSURFACE9 texsurf;
309                renderMesh->textures[0]->GetSurfaceLevel(0, &texsurf);
310                D3DSURFACE_DESC desc;
311                texsurf->GetDesc(&desc);
312                renderMesh->rayTraceMaterial = new TexturedMaterial(lrect.pBits, lrect.Pitch, desc.Width);
313                texsurf->Release();
314                renderMesh->textures[0]->UnlockRect(0);
315        }
316        else
317                renderMesh->rayTraceMaterial = new Material(Vector(1.0f, 1.0f, 1.0f), Vector(0.0f, 0.0f, 0.0f), 1.0);
318
319        //create a TriangleMesh for ray-tracing
320        renderMesh->rayTraceMesh = new TriangleMesh(renderMesh->rayTraceMaterial, indexData, renderMesh->mesh->GetNumFaces(),
321                vertexData, renderMesh->mesh->GetNumVertices());
322
323        vertexBuffer->Unlock();
324        indexBuffer->Unlock();
325        vertexBuffer->Release();
326        indexBuffer->Release();
327
328        //generate edge lines for seamless texture atlas rendering
329        renderMesh->buildEdgeVertexBuffer(device);
330
331        //store completed mesh
332        renderMeshes.push_back(renderMesh);
333}
334
335LPDIRECT3DTEXTURE9 PathMapEffect::loadTexture(LPCWSTR fileName)
336{
337        if(fileName == NULL || wcscmp(fileName, L"") == 0)
338                return NULL;
339        wchar_t* mediaFileName = new wchar_t[wcslen(fileName) + 64];
340        //we assume the x file was in folder .\media
341        wcscpy(mediaFileName, L"media\\");
342        wcscat(mediaFileName, fileName);
343        LPDIRECT3DTEXTURE9 tex;
344
345        D3DXIMAGE_INFO bobo;
346        if(S_OK !=
347                D3DXCreateTextureFromFileEx(device, mediaFileName, D3DX_DEFAULT, D3DX_DEFAULT, 1, 0,
348                D3DFMT_FROM_FILE, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, &bobo, NULL, &tex
349                ))
350        {
351                 MessageBox(NULL, mediaFileName, L"Could not load texture file!", MB_OK);
352                 return NULL;
353        }
354       
355        materialTextures.push_back(tex);
356        return tex;
357}
358
359void PathMapEffect::releaseTextures()
360{
361        std::vector<LPDIRECT3DTEXTURE9>::iterator i = materialTextures.begin();
362        while(i != materialTextures.end())
363        {
364                (*i)->Release();
365                i++;
366        }
367}
368
369void PathMapEffect::releaseMeshes()
370{
371        std::vector<PathMapEffect::RenderMesh*>::iterator i = renderMeshes.begin();
372        while(i != renderMeshes.end())
373        {
374                (*i)->mesh->Release();
375                (*i)->materialBuffer->Release();
376                delete (*i)->rayTraceMesh;
377                delete (*i)->rayTraceMaterial;
378                if((*i)->edgeVertexBuffer)
379                        (*i)->edgeVertexBuffer->Release();
380                delete *i;
381                i++;
382        }
383}
384
385void PathMapEffect::renderWithPRM()
386{
387        // first pass: render depth
388
389        device->SetRenderTarget(0, fakeSurface);
390        device->SetDepthStencilSurface(depthMapDepthStencilBuffer);
391        device->Clear( 0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(255, 0, 0, 0), 1.0f, 0 );
392        //no color writes
393        device->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
394        //render back faces (avoids Z-fighting, no need for comparison bias)
395        device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
396       
397        if( SUCCEEDED( device->BeginScene() ) )
398        {
399                effect->SetTechnique("Depth");
400                UINT nPasses;
401                effect->Begin(&nPasses, 0);
402                effect->BeginPass(0);
403                //loop through all entities, all mesh subsets, set proper transformations
404
405                std::vector<PathMapEffect::Entity>::iterator entityIterator = entities.begin();
406                while(entityIterator != entities.end())
407                {
408                        effect->SetMatrix("modelToProjMatrix",
409                                &( entityIterator->modelWorldTransform * *lightCamera->GetViewMatrix() * *lightCamera->GetProjMatrix() ) );
410                        effect->CommitChanges();
411                        unsigned int nSubsets = entityIterator->renderMesh->nSubsets;
412                        for(int i = 0; i< nSubsets; i++)
413                        {
414                                entityIterator->renderMesh->mesh->DrawSubset(i);
415                        }
416                        entityIterator++;
417                }
418
419                effect->EndPass();
420                effect->End();
421                device->EndScene();
422        }
423
424        //reset front face rendering, color writes
425        device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
426        HRESULT hr = S_OK;
427        hr = device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA| D3DCOLORWRITEENABLE_BLUE| D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED);
428
429        // 2. pass: compute weights
430
431        // simple parallel computation for all pixels: no 3D, depth, shadows, only a full-texture quad
432        hr = device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
433        hr = device->SetRenderState(D3DRS_STENCILENABLE, false);
434        hr = device->SetRenderTarget(0,weightsSurface);
435        hr = device->SetDepthStencilSurface(NULL);
436        D3DXVECTOR3 lightPos = *lightCamera->GetEyePt();
437        D3DXVECTOR3 lightDir = *lightCamera->GetWorldAhead();
438        lightDir /= D3DXVec3Length( &lightDir );
439        float ffl = parameters->Get(fLightScale) * 1.0f;
440        D3DXVECTOR3 lightPower(ffl, ffl, ffl);
441
442        device->Clear( 0, NULL, D3DCLEAR_TARGET,        D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
443
444        if( SUCCEEDED( device->BeginScene() ) ){
445                if( effect != NULL ){
446                        D3DXHANDLE hTechnique = NULL;
447                        hTechnique = effect->GetTechniqueByName((LPSTR)"ComputeWeights");
448                        if(hTechnique==NULL){
449                                return;
450                        }
451                        effect->SetTechnique( hTechnique );
452
453                        UINT nPasses = 0;
454                        effect->Begin( &nPasses, 0 );
455                        for(UINT j=0;j<nPasses;j++){
456                                effect->BeginPass(j);
457                                hr = effect->SetTexture("radions", radionTexture);
458                                static float opttme[9] = {0.5f, 0.0f, 0.0f,
459                                                                                0.0f, -0.5f, 0.0f,
460                                                                                0.5f + (0.5f / DEPTHMAPRES), 0.5f + (0.5f / DEPTHMAPRES), 1.0f};
461
462                                //set global params
463                                effect->SetFloatArray("occProjToTexMatrix", opttme, 9);
464                                effect->SetMatrix("occWorldToProjMatrix", &(*lightCamera->GetViewMatrix() * *lightCamera->GetProjMatrix()));
465
466                                effect->SetTexture("depthMap", depthMapTexture);
467                                hr = effect->SetInt("nRadionColumns", NRADIONS / 4096);
468                                hr = effect->SetFloatArray("lightPower", (float*)&lightPower, 3);
469                                hr = effect->SetFloatArray("lightPos", (float*)&lightPos, 3);
470                                hr = effect->SetFloatArray("lightDir", (float*)&lightDir, 3);
471                                effect->CommitChanges();
472                                drawFullScreenQuad(device);
473                                effect->EndPass();
474                        }
475                        effect->End();
476                }
477                device->EndScene();
478        }
479
480        // read the weights back
481
482        D3DLOCKED_RECT rData;
483        hr = device->GetRenderTargetData(weightsSurface, sysMemWeightsSurface);
484        hr =  sysMemWeightsSurface->LockRect(&rData, NULL, D3DLOCK_READONLY);
485        float* allEntryWeights = (float*)rData.pBits;
486
487        // average weights per cluster
488        float sumWeightsAll = 0.0;
489        unsigned int iRadion = 0;
490        for(int iCluster=0; iCluster < NCLUSTERS; iCluster++)
491        {
492                weights[iCluster] = 0.0;
493                float clusterrad = 0.0;
494                for(int clusterSummer=0; clusterSummer < clusterLenghts[iCluster]; clusterSummer++, iRadion++)
495                {
496                        float radrad = bushStarters[iRadion].radiance.sum();
497                        weights[iCluster] += allEntryWeights[iRadion] * radrad;
498                        clusterrad += radrad;
499                }
500                weights[iCluster] /= clusterrad; //(double)clusterLenghts[iCluster];
501//              if(iCluster != TEST_CLUST)
502//                      weights[iCluster] = 0.0;
503//              if(weights[iCluster] > 0.005)
504//                      weights[iCluster] = 0.005;
505                sumWeightsAll += weights[iCluster];
506        }
507        sysMemWeightsSurface->UnlockRect();
508
509        // 3. pass: render scene using weights to combine PRM texture atlases
510
511       
512        device->SetRenderTarget(0, frameColorBuffer);
513        device->SetDepthStencilSurface(frameDepthStencilBuffer);
514        // use backface culling, depth test
515        hr = device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
516        hr = device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
517
518        device->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,     D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
519       
520        if( SUCCEEDED( device->BeginScene() ) )
521        {
522                effect->SetTechnique("walk");
523                UINT nPasses;
524                effect->Begin(&nPasses, 0);
525                effect->BeginPass(0);
526
527                static float opttme[9] = {0.5f, 0.0f, 0.0f,
528                                                                0.0f, -0.5f, 0.0f,
529                                                                0.5f + (0.5f / DEPTHMAPRES), 0.5f + (0.5f / DEPTHMAPRES), 1.0f};
530
531                //set global params
532                effect->SetFloatArray("occProjToTexMatrix", opttme, 9);
533                effect->SetMatrix("occWorldToProjMatrix", &(*lightCamera->GetViewMatrix() * *lightCamera->GetProjMatrix()));
534
535                effect->SetTexture("depthMap", depthMapTexture);
536
537                //loop through entities
538                std::vector<PathMapEffect::Entity>::iterator entityIterator = entities.begin();
539                while(entityIterator != entities.end())
540                {
541                        //set entity params
542                        // nearestIdx -> bushId
543                        float weightsa[NCLUSTERSPERENTITY];
544                        for(unsigned int y=0; y<NCLUSTERSPERENTITY; y++)
545                                weightsa[y] = weights[entityIterator->nearClusterIndices[y]];
546                        //## could sort weightsa, indicesa and use first few
547                        hr = effect->SetFloatArray("weightsa", weightsa, NCLUSTERSPERENTITY);
548                        INT* pr = (INT*)entityIterator->nearClusterIndices;
549                        hr = effect->SetIntArray("indicesa", (INT*)entityIterator->nearClusterIndices, NCLUSTERSPERENTITY);
550                        effect->SetMatrix("modelToWorldMatrix", &entityIterator->modelWorldTransform);
551                        effect->SetMatrix("inverseTransposedModelToWorldMatrix", &entityIterator->inverseTransposedModelWorldTransform);
552                        D3DXMATRIX t = entityIterator->modelWorldTransform;
553                        if(parameters->Get(bLookFromLight))
554                                effect->SetMatrix("modelToProjMatrix", &(entityIterator->modelWorldTransform * *lightCamera->GetViewMatrix()  * *lightCamera->GetProjMatrix()  ));
555                        else
556                                effect->SetMatrix("modelToProjMatrix", &(entityIterator->modelWorldTransform * *camera->GetViewMatrix()  * *camera->GetProjMatrix()  ));
557
558                        effect->SetTexture("filteredAtlas", entityIterator->prmTexture);
559                        hr = effect->SetFloatArray("lightPower", (float*)&lightPower, 3);
560                        hr = effect->SetFloatArray("lightPos", (float*)&lightPos, 3);
561                        hr = effect->SetFloatArray("lightDir", (float*)&lightDir, 3);
562
563                        unsigned int nSubsets = entityIterator->renderMesh->nSubsets;
564                        for(int i = 0; i< nSubsets; i++)
565                        {
566                                //set subset material texture
567                                if(entityIterator->renderMesh->textures[i])
568                                        effect->SetTexture("brdfMap", entityIterator->renderMesh->textures[i]);
569                                else
570                                        effect->SetTexture("brdfMap", emptyTexture);
571                                effect->CommitChanges();
572                                entityIterator->renderMesh->mesh->DrawSubset(i);
573                        }
574                        entityIterator++;
575                }
576                effect->EndPass();
577                effect->End();
578                device->EndScene();
579        }
580}
581
582HRESULT PathMapEffect::RenderMesh::setVertexFormat(DWORD fvf, LPDIRECT3DDEVICE9 device)
583{
584        LPD3DXMESH tempMesh;
585
586        //clone the mesh to the appropriate format
587    HRESULT hr = mesh->CloneMeshFVF( mesh->GetOptions(),
588                                  fvf ,
589                                  device, &tempMesh );
590        if(hr == S_OK)
591        {
592                DWORD* padj = new DWORD[mesh->GetNumFaces() * 3];
593                mesh->GenerateAdjacency(0.00001f, padj);
594                delete padj;
595                //forget he old mesh
596                mesh->Release();
597                //use the cloned mesh
598                mesh = tempMesh;
599        }
600        return hr;
601}
602
603void PathMapEffect::renderFullScreen(float depth)
604{
605        float fLeftU = 0.0f, fTopV = 0.0f, fRightU = 1.0f, fBottomV = 1.0f;
606
607    D3DSURFACE_DESC dtdsdRT;
608    PDIRECT3DSURFACE9 pSurfRT;
609
610    // Acquire render target width and height
611    device->GetRenderTarget(0, &pSurfRT);
612    pSurfRT->GetDesc(&dtdsdRT);
613    pSurfRT->Release();
614
615    // Ensure that we're directly mapping texels to pixels by offset by 0.5
616    // For more info see the doc page titled "Directly Mapping Texels to Pixels"
617    FLOAT fWidth5 = (FLOAT)dtdsdRT.Width - 0.5f;
618    FLOAT fHeight5 = (FLOAT)dtdsdRT.Height - 0.5f;
619
620    // Draw the quad
621        struct D3DVERTEX{
622                D3DXVECTOR3 pos;
623                D3DXVECTOR2 tex0;
624        };
625
626    D3DVERTEX svQuad[4];
627
628    svQuad[0].pos=D3DXVECTOR3(-1, 1, depth);
629    svQuad[0].tex0 = D3DXVECTOR2(fLeftU, fTopV);
630
631    svQuad[1].pos = D3DXVECTOR3(1, 1, depth);
632    svQuad[1].tex0 = D3DXVECTOR2(fRightU, fTopV);
633
634    svQuad[2].pos = D3DXVECTOR3(-1, -1, depth);
635    svQuad[2].tex0 = D3DXVECTOR2(fLeftU, fBottomV);
636
637    svQuad[3].pos = D3DXVECTOR3(1, -1, depth);
638    svQuad[3].tex0 = D3DXVECTOR2(fRightU, fBottomV);
639       
640        device->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE);
641        device->SetFVF(D3DFVF_XYZ | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0));
642    device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, svQuad, sizeof(D3DVERTEX));
643}
644
645void PathMapEffect::move(float fElapsedTime)
646{
647        //apply some rotation to one of the entities
648        if(parameters->Get(bTurbo))
649        {
650                camera->FrameMove(fElapsedTime * 10.0f);
651                lightCamera->FrameMove(fElapsedTime * 10.0f);
652        }
653        else
654        {
655                camera->FrameMove(fElapsedTime);
656                lightCamera->FrameMove(fElapsedTime);
657        }
658/*      D3DXMATRIX rot;
659        D3DXMatrixRotationY(&rot, fElapsedTime * 0.1f);
660        D3DXMatrixMultiply( &entities.at(0).modelWorldTransform,
661                                                &rot,
662                                                &entities.at(0).modelWorldTransform);
663        D3DXMatrixInverse(  &entities.at(0).inverseTransposedModelWorldTransform, NULL,
664                                                &entities.at(0).modelWorldTransform);
665        D3DXMatrixTranspose( &entities.at(0).inverseTransposedModelWorldTransform, &entities.at(0).inverseTransposedModelWorldTransform);
666
667        if(entities.size() > 1)
668        {
669                D3DXMatrixTranslation(&entities.at(1).modelWorldTransform, 0.0f, parameters->Get(fSecondModelHeight) * 5.0f , 0.0f);
670                D3DXMatrixTranslation(&entities.at(1).inverseTransposedModelWorldTransform, 0.0f, -parameters->Get(fSecondModelHeight) * 5.0f , 0.0f);
671        }*/
672}
673
674LRESULT PathMapEffect::handleMessage( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
675
676{
677        if(parameters->Get(bMoveLight))
678                return lightCamera->HandleMessages(hWnd, uMsg, wParam, lParam);
679        else
680                return camera->HandleMessages(hWnd, uMsg, wParam, lParam);
681}
682
683void PathMapEffect::addUiParameters(Parameters* parameters)
684{
685        PathMapEffect::parameters = parameters;
686        parameters->Add( bLookFromLight, "Look from light", 1);
687        parameters->Add( bMoveLight, "Move light", 1);
688        parameters->Add( bDots, "Entry points", 1);
689        parameters->Add( bTurbo, "Turbo", 1);
690        parameters->Add( fLightScale, "Tone scale", 100, 'V', 'B', convert100);
691}
692
693void PathMapEffect::setUiParameterDefaults(Parameters* parameters)
694{
695}
696
697Parameters*     PathMapEffect::parameters = NULL;
698
699void PathMapEffect::render()
700{
701        if(method == Method::PRM)
702                renderWithPRM();
703        else
704                showPRMTexture();
705        if(parameters->Get(bDots))
706        {
707                float psf = 8.0f;
708                HRESULT hr = device->SetRenderState(D3DRS_POINTSIZE, *((DWORD*)&psf));
709                hr = device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
710                if( SUCCEEDED( device->BeginScene() ) )
711                {
712                        D3DXHANDLE hTechnique = NULL;
713                        hTechnique = effect->GetTechniqueByName((LPSTR)"Dots");
714                        effect->SetTechnique( hTechnique );
715                        UINT nPasses = 0;
716                        effect->Begin( &nPasses, 0 );
717                        for(UINT j=0;j<nPasses;j++){
718                                effect->BeginPass(j);
719                                        hr = effect->SetTexture("depthMap",depthMapTexture);
720                                        if(parameters->Get(bLookFromLight))
721                                                effect->SetMatrix("worldToProjMatrix", &(*lightCamera->GetViewMatrix()  * *lightCamera->GetProjMatrix()  ));
722                                        else
723                                                effect->SetMatrix("worldToProjMatrix", &(*camera->GetViewMatrix()  * *camera->GetProjMatrix()  ));
724
725                                                        static float opttme[9] = {0.5f, 0.0f, 0.0f,
726                                                                0.0f, -0.5f, 0.0f,
727                                                                0.5f + (0.5f / DEPTHMAPRES), 0.5f + (0.5f / DEPTHMAPRES), 1.0f};
728
729                                        effect->SetFloatArray("occProjToTexMatrix", opttme, 9);
730                                        D3DXVECTOR3 lightPos = *lightCamera->GetEyePt();
731                                        hr = effect->SetFloatArray("lightPos", (float*)&lightPos, 3);
732                                        effect->CommitChanges();
733                                        hr = device->SetFVF(D3DFVF_XYZ |  D3DFVF_NORMAL);
734                                        hr = device->SetStreamSource(0, starterVertexBuffer, 0, sizeof(float) * 6);
735                                        UINT offset = 0;
736                                        for(int iClusterDraw=0; iClusterDraw < NCLUSTERS; iClusterDraw++)
737                                        {
738                                                hr = effect->SetFloat("aClusterWeight", weights[iClusterDraw] * 10.0);
739                                                effect->CommitChanges();
740//                                              if(iClusterDraw == TEST_CLUST)
741                                                device->DrawPrimitive(D3DPT_POINTLIST, offset, clusterLenghts[iClusterDraw]);
742                                                offset += clusterLenghts[iClusterDraw];
743                                        }
744                                effect->EndPass();
745                        }
746                        effect->End();
747                }
748                device->EndScene();
749        }
750}
751
752void PathMapEffect::Entity::createRayTraceEntity()
753{
754        rayTraceEntity = new Transformed(renderMesh->rayTraceMesh);
755        rayTraceEntity->setTransforms(modelWorldTransform, inverseTransposedModelWorldTransform);
756}
757
758void PathMapEffect::releaseEntities()
759{
760        std::vector<PathMapEffect::Entity>::iterator entityIterator = entities.begin();
761        while(entityIterator != entities.end())
762        {
763                delete entityIterator->rayTraceEntity;
764                entityIterator->prmSurface->Release();
765                entityIterator->prmTexture->Release();
766                entityIterator++;
767        }       
768}
769
770void PathMapEffect::sampleSphereDirection(Vector& outDir)
771{
772        do{
773        outDir = Vector(-1.0 + 2.0 * (float)rand() / RAND_MAX, -1.0 + 2.0 * (float)rand() / RAND_MAX, -1.0 + 2.0 * (float)rand() / RAND_MAX);
774        }while(outDir.norm2() > 1.0);
775        outDir.normalize();
776}
777
778void PathMapEffect::sampleShootingDiffuseDirection(int depth, const Vector& normal, Vector& outDir)
779{
780        Vector u, v;
781        if(fabsf(normal[0]) < 0.9f)
782        {
783                u.set(0.0f, -normal[2], normal[1]);
784                u *= 1.0f / sqrtf(normal[2] * normal[2] + normal[1] * normal[1]);
785        }
786        else
787        {
788                u.set(normal[2], 0.0f, -normal[0]);
789                u *= 1.0f / sqrtf(normal[2] * normal[2] + normal[0] * normal[0]);
790        }
791        v.setCrossProduct(normal, u);
792
793        float phi = 2.0f * 3.14159265358979323846f * (float)rand() / RAND_MAX;
794        float xi2 = (float)rand() / RAND_MAX;
795        float cosPhi = cos(phi);
796        float sinPhi = sin(phi);
797        float cosTheta = sqrtf(xi2);
798        float sinTheta = sqrtf(1.0f - xi2);
799
800        outDir.setScaled(sinTheta * cosPhi, v);
801        outDir.addScaled(sinTheta * sinPhi, u);
802        outDir.addScaled(cosTheta, normal);
803}
804
805void PathMapEffect::createPRMTextures()
806{
807        std::vector<PathMapEffect::Entity>::iterator entityIterator = entities.begin();
808        while(entityIterator != entities.end())
809        {
810                device->CreateTexture(128 * 32, 128 * NCLUSTERSPERENTITY / 32, 1, D3DUSAGE_RENDERTARGET,D3DFMT_A16B16G16R16F,D3DPOOL_DEFAULT,&entityIterator->prmTexture,NULL);
811                entityIterator->prmTexture->GetSurfaceLevel(0,&entityIterator->prmSurface);
812                entityIterator++;
813        }       
814}
815
816void PathMapEffect::precompute()
817{
818        // generate entry points
819        for(unsigned int cRad=0; cRad < NRADIONS; cRad++)
820        {
821                Radion starter;
822                sampleSurfaceRadion(starter);
823                //sampleSurfaceRadionUniform(starter);
824                bushStarters.push_back(starter);
825        }
826
827        // sort entry radions into clusters
828        Radion* entryArray = (Radion*)&*bushStarters.begin();
829        clusterRadions(entryArray, bushStarters.size(), 0);
830        clusterRadionsKMeans();
831
832        // for every entity, find the most relevant clusters
833        std::vector<PathMapEffect::Entity>::iterator entityIterator = entities.begin();
834        while(entityIterator != entities.end())
835        {
836                entityIterator->findNearClusters(bushStarters, NCLUSTERS);
837                entityIterator++;
838        }
839
840        // for every entry radion, shoot a bush of radions, and add their
841        // contributions to all PRMs of all entities
842        unsigned int iCluster = 0;
843        std::vector<Radion> bushRadions;
844        for(int iStarter = 0; iStarter < NRADIONS; )
845        {
846                bushRadions.clear();
847                for(int iric=0; iric < clusterLenghts[iCluster]; iric++, iStarter++)
848                        shootRadionBush(bushStarters[iStarter], bushRadions);
849                std::vector<PathMapEffect::Entity>::iterator entityIterator = entities.begin();
850                while(entityIterator != entities.end())
851                {
852                        entityIterator->renderPRM(device, effect, bushRadions, iCluster, 1.0);
853                        entityIterator++;
854                }
855                iCluster++;
856        }
857}
858
859int compareX(const void* a, const void* b)
860{
861        if( ((const Radion*)a)->position.x < ((const Radion*)b)->position.x )
862                return -1;
863        else
864                return 1;
865}
866
867int compareY(const void* a, const void* b)
868{
869        if( ((const Radion*)a)->position.y < ((const Radion*)b)->position.y )
870                return -1;
871        else
872                return 1;
873}
874
875int compareZ(const void* a, const void* b)
876{
877        if( ((const Radion*)a)->position.z < ((const Radion*)b)->position.z )
878                return -1;
879        else
880                return 1;
881}
882
883int compareDirX(const void* a, const void* b)
884{
885        if( ((const Radion*)a)->normal.x < ((const Radion*)b)->normal.x )
886                return -1;
887        else
888                return 1;
889}
890
891int compareDirY(const void* a, const void* b)
892{
893        if( ((const Radion*)a)->normal.y < ((const Radion*)b)->normal.y )
894                return -1;
895        else
896                return 1;
897}
898
899int compareDirZ(const void* a, const void* b)
900{
901        if( ((const Radion*)a)->normal.z < ((const Radion*)b)->normal.z )
902                return -1;
903        else
904                return 1;
905}
906
907
908void PathMapEffect::clusterRadionsKMeans()
909{
910        Radion centroids[NCLUSTERS];
911        std::vector<Radion> clusters[NCLUSTERS];
912        //initial clusters: uniform length
913        for(unsigned int i=0; i<NCLUSTERS; i++)
914                clusterLenghts[i] = NRADIONS / NCLUSTERS;
915        for(unsigned int iKMeans = 0; iKMeans < 10; iKMeans++)
916        {
917                //find centroids
918                unsigned int iRadion = 0;
919                for(unsigned int i=0; i<NCLUSTERS; i++)
920                {
921                        centroids[i].position = Vector::RGBBLACK;
922                        centroids[i].normal = Vector::RGBBLACK;
923                        for(unsigned int iRadionInCluster=0; iRadionInCluster < clusterLenghts[i]; iRadionInCluster++, iRadion++)
924                        {
925                                centroids[i].position += bushStarters.at(iRadion).position;
926                                centroids[i].normal += bushStarters.at(iRadion).normal;
927                        }
928                        centroids[i].position *= 1.0f / (float)clusterLenghts[i];
929                        centroids[i].normal.normalize();
930                }
931               
932                for(unsigned int i=0; i<NCLUSTERS; i++)
933                        clusters[i].clear();
934
935                //sort radions to centroids
936                iRadion = 0;
937                for(unsigned int i=0; i<NCLUSTERS; i++)
938                {
939                        for(unsigned int iRadionInCluster=0; iRadionInCluster < clusterLenghts[i]; iRadionInCluster++, iRadion++)
940                        {
941                                unsigned int minimumDistanceClusterIndex = 0;
942                                float minimumDistance = FLT_MAX;
943                                for(unsigned int u=0; u<NCLUSTERS; u++)
944                                {
945                                        float dirDist = 2.0f - (bushStarters.at(iRadion).normal * centroids[u].normal);
946                                        float dist = (bushStarters.at(iRadion).position - centroids[u].position).norm() * dirDist;
947                                        if(dist < minimumDistance)
948                                        {
949                                                minimumDistanceClusterIndex = u;
950                                                minimumDistance = dist;
951                                        }
952                                }
953                                clusters[minimumDistanceClusterIndex].push_back( bushStarters.at(iRadion) );
954                        }
955                }
956                //refill bushStarters, set cluster lengths
957                iRadion = 0;
958                for(unsigned int i=0; i<NCLUSTERS; i++)
959                {
960                        clusterLenghts[i] = clusters[i].size();
961                        for(unsigned int iRadionInCluster=0; iRadionInCluster < clusterLenghts[i]; iRadionInCluster++, iRadion++)
962                        {
963                                bushStarters.at(iRadion) = clusters[i].at(iRadionInCluster);
964                        }
965                }
966                //eliminate empty clusters
967                for(unsigned int i=1; i<NCLUSTERS; i++)
968                {
969                        if(clusterLenghts[i] == 0)
970                        {
971                                clusterLenghts[i] = clusterLenghts[i-1] >> 1;
972                                clusterLenghts[i-1] -= clusterLenghts[i-1] >> 1;
973                        }
974                }
975                for(int i=NCLUSTERS - 1; i >= 0; i--)
976                {
977                        if(clusterLenghts[i] == 0)
978                        {
979                                clusterLenghts[i] = clusterLenghts[i+1] >> 1;
980                                clusterLenghts[i+1] -= clusterLenghts[i+1] >> 1;
981                        }
982                }
983        }
984}
985
986int PathMapEffect::clusterRadions(Radion* partition, int psize, char axis)
987{
988/*      if(psize < 2)
989                return 1;
990        if(axis == 0)
991                qsort(partition, psize, sizeof(Radion), compareDirX);
992        else if(axis == 1)
993                qsort(partition, psize, sizeof(Radion), compareDirY);
994        else if(axis == 2)
995                qsort(partition, psize, sizeof(Radion), compareDirZ);
996        else if(axis == 3)
997                qsort(partition, psize, sizeof(Radion), compareX);
998        else if(axis == 4)
999                qsort(partition, psize, sizeof(Radion), compareY);
1000        else if(axis == 5)
1001                qsort(partition, psize, sizeof(Radion), compareZ);
1002        clusterRadions(partition, psize >> 1, (axis+1)%6);
1003        clusterRadions(partition + (psize >> 1), psize - (psize >> 1), (axis+1)%6);
1004        return 1;
1005/*/     if(psize < 2)
1006                return 1;
1007        if(axis == 0)
1008                qsort(partition, psize, sizeof(Radion), compareX);
1009        else if(axis == 1)
1010                qsort(partition, psize, sizeof(Radion), compareY);
1011        else if(axis == 2)
1012                qsort(partition, psize, sizeof(Radion), compareZ);
1013        clusterRadions(partition, psize >> 1, (axis+1)%3);
1014        clusterRadions(partition + (psize >> 1), psize - (psize >> 1), (axis+1)%3);
1015        return 1;//*/
1016}
1017
1018
1019void PathMapEffect::shootRadionBush(Radion& starter, std::vector<Radion>& bushRadions)
1020{
1021        bushRadions.push_back(starter);
1022
1023        int nPhotonsShotForLight = 1;   //branching factor
1024        for(int iPhoton = 0; iPhoton < nPhotonsShotForLight; iPhoton++)
1025        {
1026                unsigned int depth = 0;
1027                ray.id = rayId++;
1028                ray.isShadowRay = false;
1029                ray.origin = starter.position;
1030                Vector power = starter.radiance;
1031                float prob = starter.probability;
1032                prob *= nPhotonsShotForLight;
1033                power *= 1.0f / nPhotonsShotForLight;
1034                sampleShootingDiffuseDirection(depth, starter.normal, ray.dir);
1035
1036                for(;;depth++)
1037                {
1038                        kdtree->traverse(ray, hitRec, 0.0f, FLT_MAX);
1039                        if(hitRec.isIntersect)
1040                        {
1041                                Radion nr;
1042                                nr.position = hitRec.point;
1043                                nr.normal = hitRec.normal;
1044                                nr.radiance = power;
1045                                nr.radiance %= hitRec.material->getTextureDiffuseBrdf(hitRec.texUV);
1046                                nr.probability = prob;
1047                                bushRadions.push_back(nr);
1048                        }
1049                        else
1050                                break;
1051                        if(depth >= 3)
1052                                break;
1053                        float rrRandom = (float)rand() / RAND_MAX;
1054                        float diffuseAlbedo = hitRec.material->getTextureDiffuseAlbedo(hitRec.texUV);
1055                        float idealAlbedo = hitRec.material->getTextureIdealAlbedo(hitRec.texUV);
1056                        float refractiveAlbedo = hitRec.material->getRefractiveAlbedo();
1057                        if(rrRandom < diffuseAlbedo)
1058                        {
1059                                ray.id = rayId++;
1060                                ray.isShadowRay = false;
1061                                ray.origin = hitRec.point;
1062                                power %= hitRec.material->getTextureDiffuseBrdf(hitRec.texUV);
1063                                power *= 1.0f / diffuseAlbedo;
1064                                prob *= diffuseAlbedo;
1065                                sampleShootingDiffuseDirection(depth, hitRec.normal, ray.dir);
1066                        }
1067                        else
1068                        {
1069                                rrRandom -= diffuseAlbedo;
1070                                if(rrRandom < idealAlbedo)
1071                                {
1072                                        ray.dir.setIdealReflectedDirection(ray.dir, hitRec.normal);
1073                                        ray.id = rayId++;
1074                                        ray.isShadowRay = false;
1075                                        ray.origin = hitRec.point;
1076                                        power %= hitRec.material->getIdealBrdf();
1077                                        power *= 1.0f / idealAlbedo;
1078                                        prob *= idealAlbedo;
1079                                }
1080                                else
1081                                        break;
1082                        }
1083                }
1084        }
1085}
1086
1087void PathMapEffect::sampleSurfaceRadion(Radion& starter)
1088{
1089        float randa = ((double)rand() / RAND_MAX) * entities.size();
1090//      float randa = ((double)rand() / RAND_MAX) * sumSurfaceArea;
1091        float uptonowSurfaceArea = 0.0;
1092        Entity* e = NULL;
1093        std::vector<PathMapEffect::Entity>::iterator entityIterator = entities.begin();
1094        while(entityIterator != entities.end())
1095        {
1096                uptonowSurfaceArea += 1.0f;
1097//              uptonowSurfaceArea += entityIterator->rayTraceEntity->getSurfaceArea();
1098                if(uptonowSurfaceArea >= randa)
1099                {
1100                        e = &*entityIterator;
1101                        break;
1102                }
1103                entityIterator++;
1104        }
1105
1106        e->rayTraceEntity->sampleSurface(starter);
1107
1108        float surfa = starter.radiance.z;
1109        starter.radiance = e->rayTraceEntity->getMaterial()->getTextureDiffuseBrdf(starter.radiance);
1110        starter.radiance *= (surfa / NRADIONS) * entities.size();
1111//      starter.radiance *= sumSurfaceArea / NRADIONS;
1112        starter.probability = (float)NRADIONS / (entities.size() * surfa );
1113}
1114
1115void PathMapEffect::sampleSurfaceRadionUniform(Radion& starter)
1116{
1117        float randa = ((double)rand() / RAND_MAX) * sumSurfaceArea;
1118        float uptonowSurfaceArea = 0.0;
1119        Entity* e = NULL;
1120        std::vector<PathMapEffect::Entity>::iterator entityIterator = entities.begin();
1121        while(entityIterator != entities.end())
1122        {
1123                uptonowSurfaceArea += entityIterator->rayTraceEntity->getSurfaceArea();
1124                if(uptonowSurfaceArea >= randa)
1125                {
1126                        e = &*entityIterator;
1127                        break;
1128                }
1129                entityIterator++;
1130        }
1131
1132        e->rayTraceEntity->sampleSurface(starter);
1133
1134        float surfa = starter.radiance.z;
1135        starter.radiance = e->rayTraceEntity->getMaterial()->getTextureDiffuseBrdf(starter.radiance);
1136        starter.radiance *= sumSurfaceArea / NRADIONS;
1137        starter.probability = NRADIONS / sumSurfaceArea;
1138}
1139
1140
1141void PathMapEffect::Entity::renderPRM(LPDIRECT3DDEVICE9 device,
1142                                                        LPD3DXEFFECT effect,
1143                                                        std::vector<Radion>& bushRadions,
1144                                                        unsigned int bushId,
1145                                                        float scaleFactor
1146                                                        )
1147{
1148        HRESULT hr;     UINT nPasses=1;
1149
1150        //# bushId -> nearestIdx
1151        int radinx = 0xffffff;
1152        for(int i=0; i<NCLUSTERSPERENTITY; i++)
1153                if(nearClusterIndices[i] == bushId)
1154                        radinx = i;
1155        if(radinx == 0xffffff)
1156                return;
1157
1158        hr = device->SetRenderTarget(0, prmSurface);
1159        int tilex = radinx % 32;
1160        int tiley = radinx / 32;
1161
1162        D3DVIEWPORT9 vp;
1163        vp.X = tilex * 128;                     vp.Y = tiley * 128;
1164        vp.Width = vp.Height = 128;
1165        vp.MinZ = 0.0; vp.MaxZ = 1.0;
1166
1167        //clear everything
1168        device->SetRenderTarget(0, prmSurface);
1169        device->SetDepthStencilSurface(owner->prmBlendingDepthStencilBuffer);
1170        device->SetViewport(&vp);
1171
1172        device->Clear( 0, NULL, D3DCLEAR_TARGET,
1173                                                D3DCOLOR_RGBA(0,0,0,0), 1.0f, 0 );
1174
1175        unsigned int nRadions = bushRadions.size();
1176        for(int ir=0; ir < nRadions; ir++)
1177        {
1178                // 1. pass render depth map for virtual light source
1179                device->SetRenderTarget(0, owner->fakeSurface);
1180                device->SetDepthStencilSurface(owner->depthMapDepthStencilBuffer);
1181
1182                device->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
1183
1184                device->Clear( 0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(255, 0, 0, 0), 1.0f, 0 );
1185
1186                CFirstPersonCamera radionCamera;
1187                radionCamera.SetViewParams((D3DXVECTOR3*)&bushRadions[ir].position, (D3DXVECTOR3*)&(bushRadions[ir].position + bushRadions[ir].normal));
1188                radionCamera.SetProjParams( D3DX_PI/1.9, 1.0f, 0.1f, 300.0f );
1189
1190                // render backfaces to avoid z-fighting
1191                device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
1192                if( SUCCEEDED( device->BeginScene() ) )
1193                {
1194                        effect->SetTechnique("Depth");
1195                        UINT nPasses;
1196                        effect->Begin(&nPasses, 0);
1197                        effect->BeginPass(0);
1198                        //loop through all entities, all mesh subsets, set proper transformations
1199
1200                        std::vector<PathMapEffect::Entity>::iterator entityIterator = owner->entities.begin();
1201                        while(entityIterator != owner->entities.end())
1202                        {
1203                                effect->SetMatrix("modelToProjMatrix",
1204                                        &( entityIterator->modelWorldTransform * *radionCamera.GetViewMatrix() * *radionCamera.GetProjMatrix() ) );
1205                                effect->CommitChanges();
1206                                unsigned int nSubsets = entityIterator->renderMesh->nSubsets;
1207                                for(int i = 0; i< nSubsets; i++)
1208                                {
1209                                        entityIterator->renderMesh->mesh->DrawSubset(i);
1210                                }
1211                                entityIterator++;
1212                        }
1213
1214                        effect->EndPass();
1215                        effect->End();
1216                        device->EndScene();
1217                }
1218
1219                device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
1220                device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA);
1221
1222                // blend-add contribution of virtual light source to PRM
1223                device->SetRenderTarget(0, prmSurface);
1224                device->SetDepthStencilSurface(owner->prmBlendingDepthStencilBuffer);
1225                device->SetViewport(&vp);
1226                device->SetRenderState(D3DRS_CULLMODE,  D3DCULL_NONE);
1227                device->SetRenderState(D3DRS_ALPHABLENDENABLE,  true);
1228                device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
1229                device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
1230                device->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
1231                device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
1232
1233                // use stencil to avoid adding contribution twice
1234                HRESULT hr = device->Clear( 0, NULL, D3DCLEAR_STENCIL,
1235                                        D3DCOLOR_RGBA(0,0,0,0), 1.0f, 0 );
1236                if( SUCCEEDED( device->BeginScene() ) )
1237                {
1238                        Radion radion = bushRadions[ir];
1239
1240                        if( effect != NULL ){
1241                                D3DXHANDLE hTechnique = effect->GetTechniqueByName((LPSTR)"BushToAtlas");
1242                                if(hTechnique==NULL){
1243                                        return;
1244                                }
1245                                effect->SetTechnique( hTechnique );
1246                               
1247                                effect->Begin( &nPasses, 0 );
1248                                for(UINT j=0;j<nPasses;j++){
1249                                        effect->BeginPass(j);
1250                                        Vector fakejake = bushRadions[ir].position;
1251                                        fakejake = bushRadions[ir].normal;
1252                                        fakejake = bushRadions[ir].radiance;
1253                                        hr=effect->SetFloatArray("lightPos", (float*)&bushRadions[ir].position, 3);
1254                                        hr=effect->SetFloatArray("lightDir", (float*)&bushRadions[ir].normal, 3);
1255                                        static float opttme[9] = {0.5f, 0.0f, 0.0f,
1256                                                                                        0.0f, -0.5f, 0.0f,
1257                                                                                        0.5f + (0.5f / DEPTHMAPRES), 0.5f + (0.5f / DEPTHMAPRES), 1.0f};
1258                                        effect->SetTexture("depthMap", owner->depthMapTexture);
1259
1260                                        Vector bb0 = this->rayTraceEntity->bbox.minPoint;
1261                                        Vector bb1 = this->rayTraceEntity->bbox.maxPoint;
1262                                        //effect->SetFloat("cutNearness2", (bb1 - bb0).norm2() / 200.0f);
1263                                        float nne = 5.0f / bushRadions[ir].probability;
1264                                        float onne = (bb1 - bb0).norm2() / 200.0f;
1265                                        effect->SetFloat("cutNearness2", nne);
1266                                        //effect->SetFloat("cutNearness2", 0.0f);
1267                                       
1268                                        //set global params
1269                                        effect->SetFloatArray("occProjToTexMatrix", opttme, 9);
1270                                        effect->SetMatrix("occWorldToProjMatrix", &(*radionCamera.GetViewMatrix() * *radionCamera.GetProjMatrix()));
1271                                        effect->SetMatrix("modelToWorldMatrix", &(this->modelWorldTransform));
1272                                        effect->SetMatrix("inverseTransposedModelToWorldMatrix", &(this->inverseTransposedModelWorldTransform));
1273                                        Vector scaledPower = bushRadions[ir].radiance * scaleFactor;
1274                                        hr=effect->SetFloatArray("lightPower", (float*)&scaledPower, 3);
1275                                       
1276                                        hr = device->SetRenderState(D3DRS_STENCILENABLE, true);
1277                                        hr = device->SetRenderState(D3DRS_STENCILREF, 0xffffffff);
1278                                        hr = device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
1279                                        hr = device->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE);
1280
1281                                        effect->CommitChanges();
1282
1283                                        renderMesh->mesh->DrawSubset(0);
1284
1285                                        hr = device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_NOTEQUAL);
1286                                        scaledPower = bushRadions[ir].radiance * 1.0f ;
1287                                        hr=effect->SetFloatArray("lightPower", (float*)&scaledPower, 3);
1288                                        effect->CommitChanges();
1289
1290                                        if(renderMesh->nEdges)
1291                                        {
1292                                                device->SetStreamSource(0, renderMesh->edgeVertexBuffer, 0, sizeof(D3DVERTEX));
1293                                                device->DrawPrimitive(D3DPT_LINELIST, 0, renderMesh->nEdges);
1294                                        }
1295
1296                                        effect->EndPass();
1297                                }
1298                                effect->End();
1299                        }
1300                        device->EndScene();
1301                        device->SetRenderState(D3DRS_STENCILENABLE, false);
1302                        device->SetRenderState(D3DRS_CULLMODE,  D3DCULL_CCW);
1303                        device->SetRenderState(D3DRS_ALPHABLENDENABLE,  false);
1304                        device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
1305                }
1306        }
1307}
1308
1309void PathMapEffect::drawFullScreenQuad(LPDIRECT3DDEVICE9 device, float depth, float fLeftU, float fTopV, float fRightU, float fBottomV)
1310{
1311    D3DSURFACE_DESC dtdsdRT;
1312    PDIRECT3DSURFACE9 pSurfRT;
1313
1314    // Acquire render target width and height
1315    device->GetRenderTarget(0, &pSurfRT);
1316    pSurfRT->GetDesc(&dtdsdRT);
1317    pSurfRT->Release();
1318
1319    // Ensure that we're directly mapping texels to pixels by offset by 0.5
1320    // For more info see the doc page titled "Directly Mapping Texels to Pixels"
1321    FLOAT fWidth5 = (FLOAT)dtdsdRT.Width - 0.5f;
1322    FLOAT fHeight5 = (FLOAT)dtdsdRT.Height - 0.5f;
1323
1324    // Draw the quad
1325    D3DVERTEX svQuad[4];
1326
1327    svQuad[0].pos=D3DXVECTOR3(-1, 1, depth);
1328        svQuad[0].normal=D3DXVECTOR3(0,0,0);
1329    svQuad[0].tex0 = D3DXVECTOR2(fLeftU, fTopV);
1330
1331    svQuad[1].pos = D3DXVECTOR3(1, 1, depth);
1332        svQuad[1].normal = D3DXVECTOR3(0,0,0);
1333    svQuad[1].tex0 = D3DXVECTOR2(fRightU, fTopV);
1334
1335    svQuad[2].pos = D3DXVECTOR3(-1, -1, depth);
1336        svQuad[2].normal = D3DXVECTOR3(0,0,0);
1337    svQuad[2].tex0 = D3DXVECTOR2(fLeftU, fBottomV);
1338
1339    svQuad[3].pos = D3DXVECTOR3(1, -1, depth);
1340        svQuad[3].normal = D3DXVECTOR3(0,0,0);
1341    svQuad[3].tex0 = D3DXVECTOR2(fRightU, fBottomV);
1342       
1343        device->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE);
1344        device->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0));
1345    device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, svQuad, sizeof(D3DVERTEX));
1346}
1347
1348void PathMapEffect::showPRMTexture()
1349{
1350        device->SetRenderTarget(0, frameColorBuffer);
1351        device->SetDepthStencilSurface(frameDepthStencilBuffer);
1352
1353        device->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,     D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
1354
1355        if( SUCCEEDED( device->BeginScene() ) ){
1356                if( effect != NULL ){
1357                        D3DXHANDLE hTechnique = effect->GetTechniqueByName((LPSTR)"ShowTex");
1358                        if(hTechnique==NULL){
1359                                return;
1360                        }
1361                        effect->SetTechnique( hTechnique );
1362                        UINT nPasses = 0;
1363                        effect->Begin( &nPasses, 0 );
1364                        for(UINT j=0;j<nPasses;j++){
1365                                effect->BeginPass(j);
1366               
1367                                //loop through entities
1368                                std::vector<PathMapEffect::Entity>::iterator entityIterator = entities.begin();
1369                                //while(entityIterator != entities.end())
1370                                {
1371                                        //set entity params
1372                                        effect->SetMatrix("modelToWorldMatrix", &entityIterator->modelWorldTransform);
1373                                        effect->SetMatrix("inverseTransposedModelToWorldMatrix", &entityIterator->inverseTransposedModelWorldTransform);
1374                                        D3DXMATRIX t = entityIterator->modelWorldTransform;
1375                                        if(parameters->Get(bLookFromLight))
1376                                                effect->SetMatrix("modelToProjMatrix", &(entityIterator->modelWorldTransform * *lightCamera->GetViewMatrix()  * *lightCamera->GetProjMatrix()  ));
1377                                        else
1378                                                effect->SetMatrix("modelToProjMatrix", &(entityIterator->modelWorldTransform * *camera->GetViewMatrix()  * *camera->GetProjMatrix()  ));
1379
1380                                        effect->SetTexture("filteredAtlas", entityIterator->prmTexture);
1381
1382                                        unsigned int nSubsets = entityIterator->renderMesh->nSubsets;
1383                                        for(int i = 0; i< nSubsets; i++)
1384                                        {
1385                                                //set subset material texture
1386                                                effect->SetTexture("texToShow", entityIterator->prmTexture);
1387                                                effect->CommitChanges();
1388                                                drawFullScreenQuad(device);
1389//                                              effect->CommitChanges();
1390//                                              entityIterator->renderMesh->mesh->DrawSubset(i);
1391                                        }
1392                                        entityIterator++;
1393                                }
1394                                effect->EndPass();
1395                        }
1396                        effect->End();
1397                }
1398                device->EndScene();
1399        }
1400
1401}
1402
1403void PathMapEffect::RenderMesh::buildEdgeVertexBuffer(LPDIRECT3DDEVICE9 device)
1404{
1405        LPD3DXMESH pMesh = this->mesh;
1406        DWORD* pAdj = new DWORD[3 * pMesh->GetNumFaces()];
1407        for(int r=0; r<pMesh->GetNumFaces()*3; r++)
1408                pAdj[r] = 0xffff;
1409        pMesh->ConvertPointRepsToAdjacency(NULL, pAdj);
1410
1411        LPDIRECT3DVERTEXBUFFER9 vertexBuffer;
1412        pMesh->GetVertexBuffer(&vertexBuffer);
1413        D3DVERTEX* vertexData;
1414        vertexBuffer->Lock(0,pMesh->GetNumVertices()*pMesh->GetNumBytesPerVertex(),(void**)&vertexData,0);
1415        LPDIRECT3DINDEXBUFFER9 indexBuffer;
1416        pMesh->GetIndexBuffer(&indexBuffer);
1417        unsigned short* indexData;
1418        indexBuffer->Lock(0,pMesh->GetNumFaces()*3*sizeof(unsigned short),(void**)&indexData,0);
1419
1420
1421        int countEdges = 0;
1422        for(int u=0; u<pMesh->GetNumFaces(); u++)
1423                for(int t=0; t<3; t++)
1424                        if(pAdj[u * 3 + t] >= pMesh->GetNumFaces())
1425                                countEdges++;
1426
1427        if(countEdges == 0)
1428        {
1429                edgeVertexBuffer = NULL;
1430                nEdges = 0;
1431                vertexBuffer->Unlock();
1432                indexBuffer->Unlock();
1433                SAFE_RELEASE(vertexBuffer);
1434                SAFE_RELEASE(indexBuffer);
1435                return;
1436        }
1437
1438        device->CreateVertexBuffer(2 * countEdges * pMesh->GetNumBytesPerVertex(),
1439                D3DUSAGE_WRITEONLY, pMesh->GetFVF(), D3DPOOL_DEFAULT,
1440                &edgeVertexBuffer, NULL);
1441        D3DVERTEX* pevData;
1442        edgeVertexBuffer->Lock(0, 0, (void**)&pevData, 0);
1443
1444        int iEdge = 0;
1445        for(int u=0; u<pMesh->GetNumFaces(); u++)
1446        {
1447                for(int t=0; t<3; t++)
1448                {
1449                        if(pAdj[u * 3 + t] >= pMesh->GetNumFaces())
1450                        {
1451                                unsigned short edge0 = indexData[u * 3 + t];
1452                                unsigned short edge1 = indexData[u * 3 + (t+1)%3];
1453                                unsigned short inner = indexData[u * 3 + (t+2)%3];
1454
1455                                //push vertex edge0, edge1
1456                                pevData[iEdge * 2] = vertexData[edge0];
1457                                pevData[iEdge * 2 + 1] = vertexData[edge1];
1458                               
1459                                D3DXVECTOR2 ediff =  vertexData[edge1].tex0 - vertexData[edge0].tex0;
1460                                if(fabsf(ediff.x) > fabsf(ediff.y))
1461                                {
1462                                        if(vertexData[inner].tex0.y <= vertexData[edge0].tex0.y +
1463                                                (vertexData[inner].tex0.x - vertexData[edge0].tex0.x) *
1464                                                (vertexData[edge1].tex0.y - vertexData[edge0].tex0.y) /
1465                                                (vertexData[edge1].tex0.x - vertexData[edge0].tex0.x))
1466                                        {
1467                                                pevData[iEdge * 2].tex0.y += 1.0/DBLATLASSIZE;
1468                                                pevData[iEdge * 2 + 1].tex0.y += 1.0/DBLATLASSIZE;
1469                                        }
1470                                        else
1471                                        {
1472                                                pevData[iEdge * 2].tex0.y -= 1.0/DBLATLASSIZE;
1473                                                pevData[iEdge * 2 + 1].tex0.y -= 1.0/DBLATLASSIZE;
1474                                        }
1475                                        D3DXVECTOR2 edgeDirUnitExt(1.0f, (vertexData[edge1].tex0.y - vertexData[edge0].tex0.y) /
1476                                                (vertexData[edge1].tex0.x - vertexData[edge0].tex0.x));
1477                                        edgeDirUnitExt *= 1.0/ATLASSIZE;
1478                                        if(vertexData[edge1].tex0.x > vertexData[edge0].tex0.x)
1479                                        {
1480                                                pevData[iEdge * 2].tex0 -= edgeDirUnitExt;
1481                                                pevData[iEdge * 2 + 1].tex0 += edgeDirUnitExt;
1482                                        }
1483                                        else
1484                                        {
1485                                                pevData[iEdge * 2].tex0 += edgeDirUnitExt;
1486                                                pevData[iEdge * 2 + 1].tex0 -= edgeDirUnitExt;
1487                                        }
1488                                }
1489                                else
1490                                {
1491                                        if(vertexData[inner].tex0.x <= vertexData[edge0].tex0.x +
1492                                                (vertexData[inner].tex0.y - vertexData[edge0].tex0.y) *
1493                                                (vertexData[edge1].tex0.x - vertexData[edge0].tex0.x) /
1494                                                (vertexData[edge1].tex0.y - vertexData[edge0].tex0.y))
1495                                        {
1496                                                pevData[iEdge * 2].tex0.x += 1.0/DBLATLASSIZE;
1497                                                pevData[iEdge * 2 + 1].tex0.x += 1.0/DBLATLASSIZE;
1498                                        }
1499                                        else
1500                                        {
1501                                                pevData[iEdge * 2].tex0.x -= 1.0/DBLATLASSIZE;
1502                                                pevData[iEdge * 2 + 1].tex0.x -= 1.0/DBLATLASSIZE;
1503                                        }
1504                                        D3DXVECTOR2 edgeDirUnitExt((vertexData[edge1].tex0.x - vertexData[edge0].tex0.x) /
1505                                                (vertexData[edge1].tex0.y - vertexData[edge0].tex0.y), 1.0f);
1506                                        edgeDirUnitExt *= 1.0/ATLASSIZE;
1507                                        if(vertexData[edge1].tex0.y > vertexData[edge0].tex0.y)
1508                                        {
1509                                                pevData[iEdge * 2].tex0 -= edgeDirUnitExt;
1510                                                pevData[iEdge * 2 + 1].tex0 += edgeDirUnitExt;
1511                                        }
1512                                        else
1513                                        {
1514                                                pevData[iEdge * 2].tex0 += edgeDirUnitExt;
1515                                                pevData[iEdge * 2 + 1].tex0 -= edgeDirUnitExt;
1516                                        }
1517                                }
1518
1519                                iEdge++;
1520                        }
1521                }
1522        }
1523        nEdges = iEdge;
1524
1525        edgeVertexBuffer->Unlock();
1526        vertexBuffer->Unlock();
1527        indexBuffer->Unlock();
1528        SAFE_RELEASE(vertexBuffer);
1529        SAFE_RELEASE(indexBuffer);
1530
1531        delete pAdj;
1532}
1533
1534void PathMapEffect::uploadRadions()
1535{
1536        int nRadions = bushStarters.size();
1537        struct TMR{
1538                float pos[4];
1539                float dir[4];
1540//              float pow[4];
1541        };
1542        TMR* tm = new TMR[nRadions];
1543        for(int i=0; i<nRadions; i++)
1544        {
1545//*
1546                tm[i].pos[0] = bushStarters[i].position[0];
1547                tm[i].pos[1] = bushStarters[i].position[1];
1548                tm[i].pos[2] = bushStarters[i].position[2];
1549                tm[i].pos[3] = 1.0;
1550                tm[i].dir[0] = bushStarters[i].normal[0];
1551                tm[i].dir[1] = bushStarters[i].normal[1];
1552                tm[i].dir[2] = bushStarters[i].normal[2];
1553                tm[i].dir[3] = 1.0;
1554//              tm[i].pow[0] = bushStarters[i].radiance[0];
1555//              tm[i].pow[1] = bushStarters[i].radiance[1];
1556//              tm[i].pow[2] = bushStarters[i].radiance[2];
1557//              tm[i].pow[3] = 1.0;
1558/*/
1559                tm[i].pos[0] = 0.9;
1560                tm[i].pos[1] = 0.2;
1561                tm[i].pos[2] = 0.2;
1562                tm[i].pos[3] = 1.0;
1563                tm[i].dir[0] = 0.2;
1564                tm[i].dir[1] = 0.9;
1565                tm[i].dir[2] = 0.2;
1566                tm[i].dir[3] = 1.0;
1567                tm[i].pow[0] = 0.2;
1568                tm[i].pow[1] = 0.2;
1569                tm[i].pow[2] = 0.9;     //blue
1570                tm[i].pow[3] = 0.99;
1571//*/
1572        }
1573
1574        RECT imgSize;
1575        imgSize.top = imgSize.left = 0;
1576        imgSize.bottom =  nRadions;
1577        imgSize.right = 2 * nRadions / 4096;
1578        D3DXLoadSurfaceFromMemory(radionSurface, NULL, NULL, tm, D3DFMT_A32B32G32R32F,
1579                imgSize.right * 4 * sizeof(float), NULL, &imgSize, D3DX_FILTER_NONE, 0);
1580
1581        delete [] tm;
1582}
1583
1584void PathMapEffect::fillRadionPosArray(void* pData)
1585{
1586        int nRadions = NRADIONS;
1587        struct TMR{
1588                float pos[3];
1589                float rad[3];
1590        };
1591        TMR* tm = (TMR*)pData;
1592        for(int i=0; i<nRadions; i++)
1593        {
1594                tm[i].pos[0] = bushStarters[i].position[0];
1595                tm[i].pos[1] = bushStarters[i].position[1];
1596                tm[i].pos[2] = bushStarters[i].position[2];
1597                tm[i].rad[0] = bushStarters[i].radiance[0];
1598                tm[i].rad[1] = bushStarters[i].radiance[1];
1599                tm[i].rad[2] = bushStarters[i].radiance[2];
1600        }
1601}
1602
1603const wchar_t* PathMapEffect::getWeightsString()
1604{
1605        static wchar_t ws[512];
1606        ws[0] = 0;
1607        char wan[64];
1608        float sumw = 0.0f;
1609        for(int i=0; i<33; i++)
1610        {
1611//              StrCpy(wan, L"%f ");
1612                if(i == 32)
1613                        sprintf(wan, "%.3f ", (double)sumw);
1614                else
1615                {
1616                        sumw += weights[i];
1617                        sprintf(wan, "%.3f ", (double)weights[i]);
1618                }
1619                wchar_t* wideValue = new wchar_t[MultiByteToWideChar(CP_ACP, 0, wan, -1, NULL, 0)];
1620                MultiByteToWideChar(CP_ACP, 0, wan, -1, wideValue, 511);
1621                StrCatW(ws, wideValue);
1622                delete wideValue;
1623        }
1624        return ws;
1625}
1626
1627struct ClusterDist2{
1628        unsigned int index;
1629        double dist2;
1630        ClusterDist2(unsigned int index, double dist2) {this->index = index; this->dist2 = dist2;}
1631        bool operator<(const ClusterDist2& o) const {return dist2 > o.dist2;}
1632        bool operator>(const ClusterDist2& o) const {return dist2 < o.dist2;}
1633        bool operator<=(const ClusterDist2& o) const {return dist2 >= o.dist2;}
1634        bool operator>=(const ClusterDist2& o) const {return dist2 <= o.dist2;}
1635};
1636
1637void PathMapEffect::Entity::findNearClusters(const std::vector<Radion>& starters, unsigned int nClusters)
1638{
1639        D3DXVECTOR3 cc = (D3DXVECTOR3&)rayTraceEntity->bbox.getCentre();
1640
1641        std::priority_queue<ClusterDist2> nearestClusterDists;
1642
1643        for(unsigned int iCluster = 0; iCluster < NCLUSTERS; iCluster++)
1644        {
1645                unsigned int iRadion = 0;
1646                unsigned int nRadionsPerCluster = owner->clusterLenghts[iCluster];
1647                double aClusterDist2 = 0.0;
1648                for(unsigned int iric=0; iric < nRadionsPerCluster; iric++, iRadion++)
1649                {
1650                        aClusterDist2 += (starters[iRadion++].position - cc).norm2();
1651                }
1652                nearestClusterDists.push( ClusterDist2(iCluster, aClusterDist2) );
1653        }
1654        for(unsigned int i=0; i<32; i++)
1655        {
1656                nearClusterIndices[i] = i;// nearestClusterDists.top().index;
1657                nearestClusterDists.pop();
1658        }
1659}
1660
1661
1662
1663void PathMapEffect::savePathMaps()
1664{
1665        std::fstream entryPointFile("prm\\prmEntryPoints.dat", std::ios::out | std::ios::binary);
1666
1667        for(unsigned int u=0; u < NRADIONS; u++)
1668        {
1669                entryPointFile << bushStarters.at(u);
1670        }
1671       
1672        for(unsigned int c=0; c < NCLUSTERS; c++)
1673        {
1674                entryPointFile.write((char*)&clusterLenghts[c], sizeof(unsigned int));
1675        }
1676
1677        entryPointFile.flush();
1678        entryPointFile.close();
1679
1680        unsigned int iEntity = 0;
1681        std::vector<PathMapEffect::Entity>::iterator entityIterator = entities.begin();
1682        while(entityIterator != entities.end())
1683        {
1684                wchar_t prmFileName[256];
1685                wsprintf(prmFileName, L"prm\\prm_%08d.hdr", iEntity);
1686                D3DXSaveSurfaceToFile(prmFileName, D3DXIFF_HDR, entityIterator->prmSurface, NULL, NULL);
1687                entityIterator++;
1688                iEntity++;
1689        }
1690}
1691
1692void PathMapEffect::loadPathMaps()
1693{
1694        std::fstream entryPointFile("prm\\prmEntryPoints.dat", std::ios::in | std::ios::binary);
1695
1696        bushStarters.clear();
1697
1698        for(unsigned int u=0; u < NRADIONS; u++)
1699        {
1700                Radion ri;
1701                entryPointFile >> ri;
1702                bushStarters.push_back(ri);
1703        }
1704       
1705        for(unsigned int c=0; c < NCLUSTERS; c++)
1706        {
1707                entryPointFile.read((char*)&clusterLenghts[c], sizeof(unsigned int));           
1708        }
1709
1710        entryPointFile.close();
1711
1712        unsigned int iEntity = 0;
1713        std::vector<PathMapEffect::Entity>::iterator entityIterator = entities.begin();
1714        while(entityIterator != entities.end())
1715        {
1716                entityIterator->findNearClusters(bushStarters, NCLUSTERS);
1717
1718                wchar_t prmFileName[256];
1719                wsprintf(prmFileName, L"prm\\prm_%08d.hdr", iEntity);
1720                D3DXLoadSurfaceFromFile(entityIterator->prmSurface, NULL, NULL, prmFileName, NULL, D3DX_DEFAULT, 0, NULL);
1721                entityIterator++;
1722                iEntity++;
1723        }
1724}
Note: See TracBrowser for help on using the repository browser.