source: GTP/trunk/App/Demos/Illum/pathmap/PathMapEffect.cpp @ 2212

Revision 2212, 39.5 KB checked in by szirmay, 17 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 "Entity.h"
9#include "DepthRenderStrategy.h"
10#include "FinalCompositionRenderStrategy.h"
11#include "SubEntity.h"
12#include "Entity.h"
13#include "Mesh.h"
14#include "L.h"
15#include "shlwapi.h"
16#include <queue>
17#include <fstream>
18
19#define MAXNCLUSTERS 512
20//#define GENERATE_PATH_MAPS
21
22//! D3D vector-matrix multiplication
23D3DVECTOR operator *(const D3DVECTOR& v, const D3DMATRIX& m)
24{
25        D3DVECTOR r;
26        r.x = v.x * m._11 + v.y * m._21 + v.z * m._31 + m._41;
27        r.y = v.x * m._12 + v.y * m._22 + v.z * m._32 + m._42;
28        r.z = v.x * m._13 + v.y * m._23 + v.z * m._33 + m._43;
29        float h = v.x * m._14 + v.y * m._24 + v.z * m._34 + m._44;
30        if(h > 0.00001f || h < 0.00001f)
31        {
32                r.x /= h;
33                r.y /= h;
34                r.z /= h;
35        }
36        return r;
37}
38
39//! method name strings to be displayed on screen
40const wchar_t* PathMapEffect::Method::methodNames[10] =
41{
42        L"PRM",
43        L"PRM texture",
44        L"_",
45        L"_"
46        , NULL, NULL, NULL, NULL, NULL, NULL
47};
48
49//! method constants
50const PathMapEffect::Method PathMapEffect::Method::PRM(0);
51const PathMapEffect::Method PathMapEffect::Method::SHOWTEX(1);
52const PathMapEffect::Method PathMapEffect::Method::LAST(2);
53
54//! constructor
55PathMapEffect::PathMapEffect(LPDIRECT3DDEVICE9 device,
56                char* prmDirectory,
57                char* meshDirectory,
58                char* mediaDirectory,
59                char* levelFileName,
60                char* materialFileName,
61                bool segmentMeshes,
62                bool computePRM,
63                unsigned int nEntryPoints,
64                unsigned int nClusters,
65                unsigned int depthMapResolution
66                )
67:method(Method::PRM)
68{
69        testClusterId = 0;
70
71        NRADIONS = 4096 * (nEntryPoints / 4096);
72        NCLUSTERS = nClusters;
73        DEPTHMAPRES     = depthMapResolution;
74        this->SEGMENTMESHES = segmentMeshes;
75
76        weights = new float[NCLUSTERS];
77        clusterLenghts = new unsigned int[NCLUSTERS];
78
79        clusterSweepCurrentIndex = 0;
80
81        rayId = 1;
82        this->device = device;
83
84        //first person camera allows more freedom of movement
85        camera = new CFirstPersonCamera();
86        lightCamera = new CFirstPersonCamera();
87
88        HRESULT hr;
89        DWORD effectCompileFlag=0;
90       
91        LPD3DXBUFFER compilationErrors;
92        if(FAILED(
93                hr =
94                        D3DXCreateEffectFromFile(
95                                device,
96                                L"pathMap.fx",
97                                NULL,
98                                NULL,
99                                0,
100                                NULL,
101                                &effect,
102                                &compilationErrors) )){
103                MessageBoxA( NULL, (LPSTR)compilationErrors->GetBufferPointer(), "Failed to load effect file!", MB_OK);
104                exit(-1);
105        }
106
107        //store buffers so we can reset them after rendering to texture render targets
108        device->GetRenderTarget(0, &frameColorBuffer);
109        device->GetDepthStencilSurface(&frameDepthStencilBuffer);
110       
111        wcscpy(this->mediaDirectory, L::l+mediaDirectory);
112        wcscpy(this->meshDirectory, L::l+meshDirectory);
113        wcscpy(this->prmDirectory, L::l+prmDirectory);
114
115        //load empty texture
116        wcscpy(this->levelFileName, L::l+mediaDirectory);
117        wcscat(this->levelFileName, L"\\");
118        wcscat(this->levelFileName, L::l+levelFileName);
119
120        wcscpy(this->materialFileName, L::l+mediaDirectory);
121        wcscat(this->materialFileName, L"\\");
122        wcscat(this->materialFileName, L::l+materialFileName);
123
124        wchar_t emptyTextureName[256];
125        wcscpy(emptyTextureName, L::l+mediaDirectory);
126        wcscat(emptyTextureName, L"\\");
127        wcscat(emptyTextureName, L"empty.bmp");
128
129        D3DXCreateTextureFromFile(device, emptyTextureName, &emptyTexture);
130
131        //set up a scene
132
133        xMaterials = XMLNode::openFileHelper(this->materialFileName, L"materials");
134//      loadScene("media\\space.txt");
135        loadScene(LC::c-this->levelFileName);
136
137//      loadMesh( L"media\\fighter.x", 0, "", 1);
138
139        //compute the surface area of the complete geometry. useful for random sampling.
140        sumSurfaceArea = 0.0;
141        std::vector<Entity*>::iterator entityIterator = entities.begin();
142        while(entityIterator != entities.end())
143        {
144                sumSurfaceArea += (*entityIterator)->getSurfaceArea();
145                entityIterator++;
146        }
147
148        //initialize camera
149//      camera->SetViewParams( &D3DXVECTOR3(0.0f, 0.0f, 4.0f), &D3DXVECTOR3(0.0f, 0.0f, 0.0f));
150        camera->SetViewParams( &D3DXVECTOR3(0.0f, 0.0f, 0.0f), &D3DXVECTOR3(0.0f, 0.0f, 1.0f));
151        D3DSURFACE_DESC fbdesc;
152        frameColorBuffer->GetDesc(&fbdesc);
153        camera->SetProjParams( D3DX_PI/2, (float)fbdesc.Width / fbdesc.Height, 0.1f, 300.0f );
154
155        //set up spotlight
156        lightCamera->SetViewParams( &D3DXVECTOR3(5.0f, 0.0f, 0.0f), &D3DXVECTOR3(0.0f, 0.0f, 0.0f));
157        lightCamera->SetProjParams( D3DX_PI/1.9, 1.0f, 0.1f, 300.0f );
158
159        //create ray tracing kd-tree containing ray-traceable versions of entities
160        {
161                std::vector<Intersectable*> rayTraceEntities;
162                std::vector<Entity*>::iterator entityIterator = entities.begin();
163                while(entityIterator != entities.end())
164                {
165                        (*entityIterator)->gatherRayTraceEntities(rayTraceEntities);
166                        entityIterator++;
167                }
168                Intersectable** objs = (Intersectable**)&*rayTraceEntities.begin();
169                kdtree = new KDTree(objs, rayTraceEntities.size());
170        }
171
172        //create dummy render target texture for depth map rendering
173        device->CreateTexture(DEPTHMAPRES, DEPTHMAPRES, 1, D3DUSAGE_RENDERTARGET, D3DFMT_R32F, D3DPOOL_DEFAULT, &fakeTexture, NULL);
174        fakeTexture->GetSurfaceLevel(0, &fakeSurface);
175
176        //create a depthstencil texture for depth map rendering
177        device->CreateTexture(DEPTHMAPRES, DEPTHMAPRES, 1,
178                D3DUSAGE_DEPTHSTENCIL, D3DFMT_D24X8, D3DPOOL_DEFAULT, &depthMapTexture, NULL);
179        depthMapTexture->GetSurfaceLevel(0, &depthMapDepthStencilBuffer);
180
181        if(computePRM)
182                precompute();
183        else
184                loadPathMaps();
185
186        if(computePRM || segmentMeshes)
187                saveScene("processedMeshes\\processed.level");
188
189        //create a texture for radion data (will be used for weight computations on the GPU)
190        device->CreateTexture(2 * NRADIONS / 4096, 4096, 1, 0, D3DFMT_A32B32G32R32F, D3DPOOL_DEFAULT, &radionTexture, NULL);
191        radionTexture->GetSurfaceLevel(0, &radionSurface);
192
193        //fill texture with data
194        uploadRadions();
195
196        //create weights render target
197        device->CreateTexture(4096, NRADIONS / 4096, 1, D3DUSAGE_RENDERTARGET, D3DFMT_R32F, D3DPOOL_DEFAULT, &weightsTexture, NULL);
198        weightsTexture->GetSurfaceLevel(0, &weightsSurface);
199
200        //create a sytem memory duplicate of the weights render target to be able to read back weights data
201        device->CreateTexture(4096, NRADIONS / 4096, 1, 0, D3DFMT_R32F, D3DPOOL_SYSTEMMEM, &sysMemWeightsTexture, NULL);
202        sysMemWeightsTexture->GetSurfaceLevel(0, &sysMemWeightsSurface);
203
204        //create aggr weights render target
205        device->CreateTexture(MAXNCLUSTERS, 1, 1, D3DUSAGE_RENDERTARGET, D3DFMT_R32F, D3DPOOL_DEFAULT, &aggrWeightsTexture, NULL);
206        aggrWeightsTexture->GetSurfaceLevel(0, &aggrWeightsSurface);
207
208        //create a vertex buffer to be able to visualize entry radion positions
209        device->CreateVertexBuffer(NRADIONS * sizeof(float) * 6, D3DUSAGE_WRITEONLY, D3DFVF_XYZ | D3DFVF_NORMAL, D3DPOOL_DEFAULT,
210                &starterVertexBuffer, NULL);
211        void* pData;
212        starterVertexBuffer->Lock(0, 0, &pData, 0);
213        fillRadionPosArray(pData);
214        starterVertexBuffer->Unlock();
215
216        if(computePRM)
217                savePathMaps();
218}
219
220PathMapEffect::~PathMapEffect(void)
221{
222        delete weights;
223        delete clusterLenghts;
224
225        //release all resources allocated in the constructor
226        starterVertexBuffer->Release();
227
228        depthMapTexture->Release();
229        depthMapDepthStencilBuffer->Release();
230        fakeTexture->Release();
231        fakeSurface->Release();
232
233        sysMemWeightsTexture->Release();
234        sysMemWeightsSurface->Release();
235        weightsTexture->Release();
236        weightsSurface->Release();
237        aggrWeightsTexture->Release();
238        aggrWeightsSurface->Release();
239        radionTexture->Release();
240        radionSurface->Release();
241
242        delete kdtree;
243        emptyTexture->Release();
244        releaseTextures();
245        releaseMeshes();
246        releaseEntities();
247
248        frameColorBuffer->Release();
249        frameDepthStencilBuffer->Release();
250
251        effect->Release();
252        delete camera;
253        delete lightCamera;
254}
255
256void PathMapEffect::loadMesh(DWORD fileType, LPCWSTR fileName, LPCWSTR ogreName, int prmAtlasSize, const char* name, int dividePcs, bool generateUV, bool generateTBN)
257{
258        wchar_t mFileName[512];
259        wcscpy(mFileName, this->mediaDirectory);
260        wcscat(mFileName, L"\\");
261        wcscat(mFileName, fileName);
262        Mesh* mesh = new Mesh(this, fileType, mFileName, ogreName, prmAtlasSize, name, dividePcs, generateUV, generateTBN);
263        meshes.push_back(mesh);
264}
265
266LPDIRECT3DTEXTURE9 PathMapEffect::loadTexture(LPCWSTR fileName, Material** rayTraceMaterial)
267{
268        if(fileName == NULL || wcscmp(fileName, L"") == 0)
269                return NULL;
270        int texIndex = 0;
271        std::vector<wchar_t*>::iterator nameIterator = materialTextureFileNames.begin();
272        while(nameIterator != materialTextureFileNames.end())
273        {
274                if(wcscmp( *nameIterator, fileName) == 0)
275                {
276                        *rayTraceMaterial = rayTraceMaterials.at(texIndex);
277                        return materialTextures.at(texIndex);
278                }
279                nameIterator++;
280                texIndex++;
281        }
282        wchar_t* mediaFileName = new wchar_t[wcslen(fileName) + 64];
283        //we assume the x file is the media folder
284        wcscpy(mediaFileName, this->mediaDirectory);
285        wcscat(mediaFileName, L"\\");
286        wcscat(mediaFileName, fileName);
287        LPDIRECT3DTEXTURE9 tex;
288
289        D3DXIMAGE_INFO bobo;
290        if(S_OK !=
291                D3DXCreateTextureFromFileEx(device, mediaFileName, D3DX_DEFAULT, D3DX_DEFAULT, 1, 0,
292                D3DFMT_FROM_FILE, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, &bobo, NULL, &tex
293                ))
294        {
295                 MessageBox(NULL, mediaFileName, L"Could not load texture file!", MB_OK);
296                 return NULL;
297        }
298
299        delete mediaFileName;
300
301        materialTextures.push_back(tex);
302        wchar_t* storedName = new wchar_t[wcslen(fileName)+1];
303        wcscpy(storedName, fileName);
304        materialTextureFileNames.push_back(storedName);
305
306        if(rayTraceMaterial != NULL)
307        {
308                D3DLOCKED_RECT lrect;
309                HRESULT hr = tex->LockRect(0, &lrect, NULL, D3DLOCK_READONLY);
310                LPDIRECT3DSURFACE9 texsurf;
311                tex->GetSurfaceLevel(0, &texsurf);
312                D3DSURFACE_DESC desc;
313                texsurf->GetDesc(&desc);
314                *rayTraceMaterial = new TexturedMaterial(lrect.pBits, lrect.Pitch, desc.Width);
315                texsurf->Release();
316                tex->UnlockRect(0);
317        }
318        rayTraceMaterials.push_back(*rayTraceMaterial);
319
320        return tex;
321}
322
323void PathMapEffect::releaseTextures()
324{
325        std::vector<LPDIRECT3DTEXTURE9>::iterator i = materialTextures.begin();
326        while(i != materialTextures.end())
327        {
328                (*i)->Release();
329                i++;
330        }
331
332        std::vector<Material*>::iterator z = rayTraceMaterials.begin();
333        while(z != rayTraceMaterials.end())
334        {
335                delete (*z);
336                z++;
337        }
338
339        std::vector<wchar_t*>::iterator c = materialTextureFileNames.begin();
340        while(c != materialTextureFileNames.end())
341        {
342                delete [] (*c);
343                c++;
344        }
345}
346
347void PathMapEffect::releaseMeshes()
348{
349        std::vector<Mesh*>::iterator i = meshes.begin();
350        while(i != meshes.end())
351        {
352                delete *i;
353                i++;
354        }
355}
356
357void PathMapEffect::renderWithPRM()
358{
359        // 1. pass: render depth
360        DepthRenderStrategy depthRenderStrategy(this);
361
362        depthRenderStrategy.camera = *lightCamera;
363        renderScene(depthRenderStrategy);
364
365        // 2. pass: compute weights
366
367        // simple parallel computation for all pixels: no 3D, depth, shadows, only a full-texture quad
368        HRESULT hr = device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
369        hr = device->SetRenderState(D3DRS_STENCILENABLE, false);
370        hr = device->SetRenderTarget(0,weightsSurface);
371        hr = device->SetDepthStencilSurface(NULL);
372        D3DXVECTOR3 lightPos = *lightCamera->GetEyePt();
373        D3DXVECTOR3 lightDir = *lightCamera->GetWorldAhead();
374        lightDir /= D3DXVec3Length( &lightDir );
375        float ffl = parameters->Get(fLightScale) * 10.0f;
376        D3DXVECTOR3 lightPower(ffl, ffl, ffl);
377
378        device->Clear( 0, NULL, D3DCLEAR_TARGET,        D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
379
380        if( SUCCEEDED( device->BeginScene() ) ){
381                if( effect != NULL ){
382                        D3DXHANDLE hTechnique = NULL;
383                        hTechnique = effect->GetTechniqueByName((LPSTR)"ComputeWeights");
384                        if(hTechnique==NULL){
385                                return;
386                        }
387                        effect->SetTechnique( hTechnique );
388
389                        UINT nPasses = 0;
390                        effect->Begin( &nPasses, 0 );
391                        for(UINT j=0;j<nPasses;j++){
392                                effect->BeginPass(j);
393                                hr = effect->SetTexture("radions", radionTexture);
394                                static float opttme[9] = {0.5f, 0.0f, 0.0f,
395                                                                                0.0f, -0.5f, 0.0f,
396                                                                                0.5f + (0.5f / DEPTHMAPRES), 0.5f + (0.5f / DEPTHMAPRES), 1.0f};
397
398                                //set global params
399                                effect->SetFloatArray("occProjToTexMatrix", opttme, 9);
400                                effect->SetMatrix("occWorldToProjMatrix", &(*lightCamera->GetViewMatrix() * *lightCamera->GetProjMatrix()));
401
402                                effect->SetTexture("depthMap", depthMapTexture);
403                                hr = effect->SetInt("nRadionColumns", NRADIONS / 4096);
404                                hr = effect->SetFloatArray("lightPower", (float*)&lightPower, 3);
405                                hr = effect->SetFloatArray("lightPos", (float*)&lightPos, 3);
406                                hr = effect->SetFloatArray("lightDir", (float*)&lightDir, 3);
407                                effect->CommitChanges();
408                                renderFullScreen();
409                                effect->EndPass();
410                        }
411                        effect->End();
412                }
413                device->EndScene();
414        }
415
416        // read the weights back
417
418        D3DLOCKED_RECT rData;
419        hr = device->GetRenderTargetData(weightsSurface, sysMemWeightsSurface);
420        hr =  sysMemWeightsSurface->LockRect(&rData, NULL, D3DLOCK_READONLY);
421        float* allEntryWeights = (float*)rData.pBits;
422
423        // average weights per cluster
424        float sumWeightsAll = 0.0;
425        unsigned int iRadion = 0;
426        for(int iCluster=0; iCluster < NCLUSTERS; iCluster++)
427        {
428                weights[iCluster] = 0.0;
429                float clusterrad = 0.0;
430                for(int clusterSummer=0; clusterSummer < clusterLenghts[iCluster]; clusterSummer++, iRadion++)
431                {
432                        float radrad = bushStarters[iRadion].radiance.sum();
433                        weights[iCluster] += allEntryWeights[iRadion] * radrad;
434                        clusterrad += radrad;
435                }
436                if(clusterrad > 0.01)
437                        weights[iCluster] /= clusterrad; //(double)clusterLenghts[iCluster];
438                else
439                        weights[iCluster] = 0.0f;
440//              if(iCluster != TEST_CLUST)
441//                      weights[iCluster] = 0.0;
442//              if(weights[iCluster] > 0.005)
443//                      weights[iCluster] = 0.005;
444                sumWeightsAll += weights[iCluster];
445        }
446        sysMemWeightsSurface->UnlockRect();
447
448        // use backface culling, depth test
449        hr = device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
450        hr = device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
451
452/*      for(int testi=0; testi < NCLUSTERS; testi++)
453                weights[testi] = 0.000;
454        weights[testClusterId] = 0.05;*/
455
456        // 3. pass: render scene using weights to combine PRM texture atlases
457
458        FinalCompositionRenderStrategy finalCompositionRenderStrategy(this);
459        finalCompositionRenderStrategy.lightDir = lightDir;
460        finalCompositionRenderStrategy.lightPos = lightPos;
461        finalCompositionRenderStrategy.lightPower = lightPower;
462
463        renderScene(finalCompositionRenderStrategy);
464
465
466/*      if(!parameters->Get(bLookFromLight))
467        if( SUCCEEDED( device->BeginScene() ) )
468        {
469                effect->SetTechnique("torch");
470                UINT nPasses;
471                effect->Begin(&nPasses, 0);
472                effect->BeginPass(0);
473
474                D3DXMATRIX scaleShip;
475                D3DXMatrixScaling(&scaleShip, 0.05f, 0.05f, 0.05f);
476
477                effect->SetTexture("brdfMap", meshes.at(meshes.size()-1)->->textures[0]);
478                effect->SetMatrix("modelToProjMatrix", &(scaleShip * *lightCamera->GetWorldMatrix() * *camera->GetViewMatrix()  * *camera->GetProjMatrix()  ));
479
480                effect->CommitChanges();
481                renderMeshes[renderMeshes.size()-1]->mesh->DrawSubset(0);
482
483                effect->EndPass();
484                effect->End();
485                device->EndScene();
486        }
487*/
488}
489
490void PathMapEffect::renderFullScreen(float depth)
491{
492        float fLeftU = 0.0f, fTopV = 0.0f, fRightU = 1.0f, fBottomV = 1.0f;
493
494    D3DSURFACE_DESC dtdsdRT;
495    PDIRECT3DSURFACE9 pSurfRT;
496
497    // Acquire render target width and height
498    device->GetRenderTarget(0, &pSurfRT);
499    pSurfRT->GetDesc(&dtdsdRT);
500    pSurfRT->Release();
501
502    // Ensure that we're directly mapping texels to pixels by offset by 0.5
503    // For more info see the doc page titled "Directly Mapping Texels to Pixels"
504    FLOAT fWidth5 = (FLOAT)dtdsdRT.Width - 0.5f;
505    FLOAT fHeight5 = (FLOAT)dtdsdRT.Height - 0.5f;
506
507    // Draw the quad
508        struct D3DVERTEXQUAD{
509                D3DXVECTOR3 pos;
510                D3DXVECTOR2 tex0;
511        };
512
513    D3DVERTEXQUAD svQuad[4];
514
515    svQuad[0].pos=D3DXVECTOR3(-1, 1, depth);
516    svQuad[0].tex0 = D3DXVECTOR2(fLeftU, fTopV);
517
518    svQuad[1].pos = D3DXVECTOR3(1, 1, depth);
519    svQuad[1].tex0 = D3DXVECTOR2(fRightU, fTopV);
520
521    svQuad[2].pos = D3DXVECTOR3(-1, -1, depth);
522    svQuad[2].tex0 = D3DXVECTOR2(fLeftU, fBottomV);
523
524    svQuad[3].pos = D3DXVECTOR3(1, -1, depth);
525    svQuad[3].tex0 = D3DXVECTOR2(fRightU, fBottomV);
526       
527        device->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE);
528        device->SetFVF(D3DFVF_XYZ | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0));
529    device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, svQuad, sizeof(D3DVERTEXQUAD));
530}
531
532void PathMapEffect::move(float fElapsedTime)
533{
534        clusterSweepCurrentIndex += fElapsedTime * 2.0f;
535        if(clusterSweepCurrentIndex > NCLUSTERS)
536                clusterSweepCurrentIndex -= NCLUSTERS;
537        //apply some rotation to one of the entities
538        if(parameters->Get(bTurbo))
539        {
540                camera->FrameMove(fElapsedTime * 10.0f);
541                lightCamera->FrameMove(fElapsedTime * 10.0f);
542        }
543        else
544        {
545                camera->FrameMove(fElapsedTime);
546                lightCamera->FrameMove(fElapsedTime);
547        }
548}
549
550LRESULT PathMapEffect::handleMessage( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
551{
552        if(uMsg == WM_KEYDOWN)
553        {
554                switch(wParam)
555                {
556                        case 'C':
557                                testClusterId = (testClusterId + NCLUSTERS - 1) % NCLUSTERS;
558                                break;
559                        case 'Z':
560                                testClusterId = (testClusterId + 1) % NCLUSTERS;
561                                break;
562                }
563        }
564
565        if(parameters->Get(bMoveLight))
566                return lightCamera->HandleMessages(hWnd, uMsg, wParam, lParam);
567        else
568                return camera->HandleMessages(hWnd, uMsg, wParam, lParam);
569
570}
571
572void PathMapEffect::addUiParameters(Parameters* parameters)
573{
574        PathMapEffect::parameters = parameters;
575        parameters->Add( bLookFromLight, "Look from light", 1);
576        parameters->Add( bMoveLight, "Move light", 1);
577        parameters->Add( bDots, "Entry points", 1);
578        parameters->Add( bTurbo, "Turbo", 1);
579        parameters->Add( fLightScale, "Tone scale", 100, '1', '2', convertLightScale);
580        parameters->Add( fIndirectLightingMode, "Lighting mode", 3, '3', '4', convertInt4);
581        parameters->Add( fTorchDistance, "Torch distance", 100, '5', '6', convertTorchDistance);
582}
583
584void PathMapEffect::setUiParameterDefaults(Parameters* parameters)
585{
586}
587
588Parameters*     PathMapEffect::parameters = NULL;
589
590void PathMapEffect::render()
591{
592        renderWithPRM();
593        if(parameters->Get(bDots))
594        {
595                float psf = 8.0f;
596                HRESULT hr = device->SetRenderState(D3DRS_POINTSIZE, *((DWORD*)&psf));
597                hr = device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
598                if( SUCCEEDED( device->BeginScene() ) )
599                {
600                        D3DXHANDLE hTechnique = NULL;
601                        hTechnique = effect->GetTechniqueByName((LPSTR)"Dots");
602                        effect->SetTechnique( hTechnique );
603                        UINT nPasses = 0;
604                        effect->Begin( &nPasses, 0 );
605                        for(UINT j=0;j<nPasses;j++){
606                                effect->BeginPass(j);
607                                        hr = effect->SetTexture("depthMap",depthMapTexture);
608                                        if(parameters->Get(bLookFromLight))
609                                                effect->SetMatrix("worldToProjMatrix", &(*lightCamera->GetViewMatrix()  * *lightCamera->GetProjMatrix()  ));
610                                        else
611                                                effect->SetMatrix("worldToProjMatrix", &(*camera->GetViewMatrix()  * *camera->GetProjMatrix()  ));
612
613                                                        static float opttme[9] = {0.5f, 0.0f, 0.0f,
614                                                                0.0f, -0.5f, 0.0f,
615                                                                0.5f + (0.5f / DEPTHMAPRES), 0.5f + (0.5f / DEPTHMAPRES), 1.0f};
616
617                                        effect->SetFloatArray("occProjToTexMatrix", opttme, 9);
618                                        D3DXVECTOR3 lightPos = *lightCamera->GetEyePt();
619                                        hr = effect->SetFloatArray("lightPos", (float*)&lightPos, 3);
620                                        effect->CommitChanges();
621                                        hr = device->SetFVF(D3DFVF_XYZ |  D3DFVF_NORMAL);
622                                        hr = device->SetStreamSource(0, starterVertexBuffer, 0, sizeof(float) * 6);
623                                        UINT offset = 0;
624                                        for(int iClusterDraw=0; iClusterDraw < NCLUSTERS; iClusterDraw++)
625                                        {
626//                                              hr = effect->SetFloat("aClusterWeight", weights[iClusterDraw] * 10.0);
627                                                hr = effect->SetFloat("aClusterWeight", (float)iClusterDraw);
628                                                effect->CommitChanges();
629//                                              if(iClusterDraw - clusterSweepCurrentIndex > -1.0 &&
630//                                                      iClusterDraw - clusterSweepCurrentIndex < 0.0   )
631//                                              if(iClusterDraw == testClusterId)
632                                                        device->DrawPrimitive(D3DPT_POINTLIST, offset, clusterLenghts[iClusterDraw]);
633                                                offset += clusterLenghts[iClusterDraw];
634                                        }
635                                effect->EndPass();
636                        }
637                        effect->End();
638                }
639                device->EndScene();
640        }
641}
642
643void PathMapEffect::releaseEntities()
644{
645        std::vector<Entity*>::iterator entityIterator = entities.begin();
646        while(entityIterator != entities.end())
647        {
648                delete *entityIterator;
649                entityIterator++;
650        }       
651}
652
653void PathMapEffect::sampleSphereDirection(Vector& outDir)
654{
655        do{
656        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);
657        }while(outDir.norm2() > 1.0);
658        outDir.normalize();
659}
660
661void PathMapEffect::sampleShootingDiffuseDirection(int depth, const Vector& normal, Vector& outDir)
662{
663        Vector u, v;
664        if(fabsf(normal[0]) < 0.9f)
665        {
666                u.set(0.0f, -normal[2], normal[1]);
667                u *= 1.0f / sqrtf(normal[2] * normal[2] + normal[1] * normal[1]);
668        }
669        else
670        {
671                u.set(normal[2], 0.0f, -normal[0]);
672                u *= 1.0f / sqrtf(normal[2] * normal[2] + normal[0] * normal[0]);
673        }
674        v.setCrossProduct(normal, u);
675
676        float phi = 2.0f * 3.14159265358979323846f * (float)rand() / RAND_MAX;
677        float xi2 = (float)rand() / RAND_MAX;
678        float cosPhi = cos(phi);
679        float sinPhi = sin(phi);
680        float cosTheta = sqrtf(xi2);
681        float sinTheta = sqrtf(1.0f - xi2);
682
683        outDir.setScaled(sinTheta * cosPhi, v);
684        outDir.addScaled(sinTheta * sinPhi, u);
685        outDir.addScaled(cosTheta, normal);
686}
687
688void PathMapEffect::precompute()
689{
690        // generate entry points
691        for(unsigned int cRad=0; cRad < NRADIONS; cRad++)
692        {
693                Radion starter;
694                sampleSurfaceRadion(starter);
695                //sampleSurfaceRadionUniform(starter);
696                bushStarters.push_back(starter);
697        }
698
699        // sort entry radions into clusters
700        Radion* entryArray = (Radion*)&*bushStarters.begin();
701        clusterRadions(entryArray, bushStarters.size(), 0);
702        clusterRadionsKMeans();
703
704        // for every entity, find the most relevant clusters
705        srand(0xef23ab32);
706        std::vector<Entity*>::iterator entityIterator = entities.begin();
707        while(entityIterator != entities.end())
708        {
709                (*entityIterator)->findNearClusters(bushStarters, NCLUSTERS);
710                (*entityIterator)->clearPRM();
711                entityIterator++;
712        }
713
714        // for every entry radion, shoot a bush of radions, and add their
715        // contributions to all PRMs of all entities
716        unsigned int iCluster = 0;
717        std::vector<Radion> bushRadions;
718        for(int iStarter = 0; iStarter < NRADIONS; )
719        {
720                bushRadions.clear();
721                for(int iric=0; iric < clusterLenghts[iCluster]; iric++, iStarter++)
722                        shootRadionBush(bushStarters[iStarter], bushRadions);
723                std::vector<Entity*>::iterator entityIterator = entities.begin();
724                while(entityIterator != entities.end())
725                {
726                        (*entityIterator)->renderPRM(bushRadions, iCluster);
727                        entityIterator++;
728                }
729                iCluster++;
730        }
731
732        //scale down multiple pixel writes
733        entityIterator = entities.begin();
734        while(entityIterator != entities.end())
735        {
736                (*entityIterator)->normalizePRM();
737                entityIterator++;
738        }
739}
740
741int compareX(const void* a, const void* b)
742{
743        if( ((const Radion*)a)->position.x < ((const Radion*)b)->position.x )
744                return -1;
745        else
746                return 1;
747}
748
749int compareY(const void* a, const void* b)
750{
751        if( ((const Radion*)a)->position.y < ((const Radion*)b)->position.y )
752                return -1;
753        else
754                return 1;
755}
756
757int compareZ(const void* a, const void* b)
758{
759        if( ((const Radion*)a)->position.z < ((const Radion*)b)->position.z )
760                return -1;
761        else
762                return 1;
763}
764
765int compareDirX(const void* a, const void* b)
766{
767        if( ((const Radion*)a)->normal.x < ((const Radion*)b)->normal.x )
768                return -1;
769        else
770                return 1;
771}
772
773int compareDirY(const void* a, const void* b)
774{
775        if( ((const Radion*)a)->normal.y < ((const Radion*)b)->normal.y )
776                return -1;
777        else
778                return 1;
779}
780
781int compareDirZ(const void* a, const void* b)
782{
783        if( ((const Radion*)a)->normal.z < ((const Radion*)b)->normal.z )
784                return -1;
785        else
786                return 1;
787}
788
789
790void PathMapEffect::clusterRadionsKMeans()
791{
792        Radion centroids[MAXNCLUSTERS];
793        std::vector<Radion> clusters[MAXNCLUSTERS];
794        //initial clusters: uniform length
795        for(unsigned int i=0; i<NCLUSTERS; i++)
796                clusterLenghts[i] = NRADIONS / NCLUSTERS;
797        for(unsigned int iKMeans = 0; iKMeans < 128; iKMeans++)
798        {
799                //find centroids
800                unsigned int iRadion = 0;
801                for(unsigned int i=0; i<NCLUSTERS; i++)
802                {
803                        centroids[i].position = Vector::RGBBLACK;
804                        centroids[i].normal = Vector::RGBBLACK;
805                        for(unsigned int iRadionInCluster=0; iRadionInCluster < clusterLenghts[i]; iRadionInCluster++, iRadion++)
806                        {
807                                centroids[i].position += bushStarters.at(iRadion).position;
808                                centroids[i].normal += bushStarters.at(iRadion).normal;
809                        }
810                        centroids[i].position *= 1.0f / (float)clusterLenghts[i];
811                        centroids[i].normal.normalize();
812                }
813               
814                for(unsigned int i=0; i<NCLUSTERS; i++)
815                        clusters[i].clear();
816
817                //sort radions to centroids
818                iRadion = 0;
819                for(unsigned int i=0; i<NCLUSTERS; i++)
820                {
821                        for(unsigned int iRadionInCluster=0; iRadionInCluster < clusterLenghts[i]; iRadionInCluster++, iRadion++)
822                        {
823                                unsigned int minimumDistanceClusterIndex = 0;
824                                float minimumDistance = FLT_MAX;
825                                for(unsigned int u=0; u<NCLUSTERS; u++)
826                                {
827                                        float dirDist = (bushStarters.at(iRadion).normal * centroids[u].normal);
828                                        float dist = (bushStarters.at(iRadion).position - centroids[u].position).norm() * pow(6.0, 1.0 - (double)dirDist);
829                                        if(dist < minimumDistance)
830                                        {
831                                                minimumDistanceClusterIndex = u;
832                                                minimumDistance = dist;
833                                        }
834                                }
835                                clusters[minimumDistanceClusterIndex].push_back( bushStarters.at(iRadion) );
836                        }
837                }
838                //refill bushStarters, set cluster lengths
839                iRadion = 0;
840                for(unsigned int i=0; i<NCLUSTERS; i++)
841                {
842                        clusterLenghts[i] = clusters[i].size();
843                        for(unsigned int iRadionInCluster=0; iRadionInCluster < clusterLenghts[i]; iRadionInCluster++, iRadion++)
844                        {
845                                bushStarters.at(iRadion) = clusters[i].at(iRadionInCluster);
846                        }
847                }
848                //eliminate empty clusters
849                for(unsigned int i=1; i<NCLUSTERS; i++)
850                {
851                        if(clusterLenghts[i] == 0)
852                        {
853                                clusterLenghts[i] = clusterLenghts[i-1] >> 1;
854                                clusterLenghts[i-1] -= clusterLenghts[i-1] >> 1;
855                        }
856                }
857                for(int i=NCLUSTERS - 1; i >= 0; i--)
858                {
859                        if(clusterLenghts[i] == 0)
860                        {
861                                clusterLenghts[i] = clusterLenghts[i+1] >> 1;
862                                clusterLenghts[i+1] -= clusterLenghts[i+1] >> 1;
863                        }
864                }
865        }
866}
867
868int PathMapEffect::clusterRadions(Radion* partition, int psize, char axis)
869{
870/*      if(psize < 2)
871                return 1;
872        if(axis == 0)
873                qsort(partition, psize, sizeof(Radion), compareDirX);
874        else if(axis == 1)
875                qsort(partition, psize, sizeof(Radion), compareDirY);
876        else if(axis == 2)
877                qsort(partition, psize, sizeof(Radion), compareDirZ);
878        else if(axis == 3)
879                qsort(partition, psize, sizeof(Radion), compareX);
880        else if(axis == 4)
881                qsort(partition, psize, sizeof(Radion), compareY);
882        else if(axis == 5)
883                qsort(partition, psize, sizeof(Radion), compareZ);
884        clusterRadions(partition, psize >> 1, (axis+1)%6);
885        clusterRadions(partition + (psize >> 1), psize - (psize >> 1), (axis+1)%6);
886        return 1;
887/*/     if(psize < 2)
888                return 1;
889        if(axis == 0)
890                qsort(partition, psize, sizeof(Radion), compareX);
891        else if(axis == 1)
892                qsort(partition, psize, sizeof(Radion), compareY);
893        else if(axis == 2)
894                qsort(partition, psize, sizeof(Radion), compareZ);
895        clusterRadions(partition, psize >> 1, (axis+1)%3);
896        clusterRadions(partition + (psize >> 1), psize - (psize >> 1), (axis+1)%3);
897        return 1;//*/
898}
899
900
901void PathMapEffect::shootRadionBush(Radion& starter, std::vector<Radion>& bushRadions)
902{
903        bushRadions.push_back(starter);
904
905        int nPhotonsShotForLight = 1;   //branching factor
906        for(int iPhoton = 0; iPhoton < nPhotonsShotForLight; iPhoton++)
907        {
908                unsigned int depth = 0;
909                ray.id = rayId++;
910                ray.isShadowRay = false;
911                ray.origin = starter.position;
912                Vector power = starter.radiance;
913                float prob = starter.probability;
914                prob *= nPhotonsShotForLight;
915                power *= 1.0f / nPhotonsShotForLight;
916                sampleShootingDiffuseDirection(depth, starter.normal, ray.dir);
917
918                for(;;depth++)
919                {
920                        kdtree->traverse(ray, hitRec, 0.0f, FLT_MAX);
921                        if(hitRec.isIntersect)
922                        {
923                                Radion nr;
924                                nr.position = hitRec.point;
925                                nr.normal = hitRec.normal;
926                                nr.radiance = power;
927                                nr.radiance %= hitRec.material->getTextureDiffuseBrdf(hitRec.texUV);
928                                nr.probability = prob;
929                                bushRadions.push_back(nr);
930                        }
931                        else
932                                break;
933                        if(depth >= 3)
934                                break;
935                        float rrRandom = (float)rand() / RAND_MAX;
936                        float diffuseAlbedo = hitRec.material->getTextureDiffuseAlbedo(hitRec.texUV);
937                        float idealAlbedo = hitRec.material->getTextureIdealAlbedo(hitRec.texUV);
938                        float refractiveAlbedo = hitRec.material->getRefractiveAlbedo();
939                        if(rrRandom < diffuseAlbedo)
940                        {
941                                ray.id = rayId++;
942                                ray.isShadowRay = false;
943                                ray.origin = hitRec.point;
944                                power %= hitRec.material->getTextureDiffuseBrdf(hitRec.texUV);
945                                power *= 1.0f / diffuseAlbedo;
946                                prob *= diffuseAlbedo;
947                                sampleShootingDiffuseDirection(depth, hitRec.normal, ray.dir);
948                        }
949                        else
950                        {
951                                rrRandom -= diffuseAlbedo;
952                                if(rrRandom < idealAlbedo)
953                                {
954                                        ray.dir.setIdealReflectedDirection(ray.dir, hitRec.normal);
955                                        ray.id = rayId++;
956                                        ray.isShadowRay = false;
957                                        ray.origin = hitRec.point;
958                                        power %= hitRec.material->getIdealBrdf();
959                                        power *= 1.0f / idealAlbedo;
960                                        prob *= idealAlbedo;
961                                }
962                                else
963                                        break;
964                        }
965                }
966        }
967}
968
969void PathMapEffect::sampleSurfaceRadion(Radion& starter)
970{
971        float randa = ((double)rand() / RAND_MAX) * entities.size();
972//&     float randa = ((double)rand() / RAND_MAX) * sumSurfaceArea;
973        float uptonowSurfaceArea = 0.0;
974        Entity* e = NULL;
975        std::vector<Entity*>::iterator entityIterator = entities.begin();
976        while(entityIterator != entities.end())
977        {
978                uptonowSurfaceArea += 1.0f;
979//&             uptonowSurfaceArea += (*entityIterator)->getSurfaceArea();
980                if(uptonowSurfaceArea >= randa)
981                {
982                        e = *entityIterator;
983                        break;
984                }
985                entityIterator++;
986        }
987
988        const Material* m = e->sampleSurface(starter);
989
990        float surfa = starter.radiance.z;
991
992        Vector rtexc = starter.radiance;
993        starter.radiance = m->getTextureDiffuseBrdf(rtexc);
994        starter.radiance *= (surfa / NRADIONS) * entities.size();
995//&     starter.radiance *= sumSurfaceArea / NRADIONS;
996        starter.probability = (float)NRADIONS / (entities.size() * surfa );
997}
998
999void PathMapEffect::sampleSurfaceRadionUniform(Radion& starter)
1000{
1001        float randa = ((double)rand() / RAND_MAX) * sumSurfaceArea;
1002        float uptonowSurfaceArea = 0.0;
1003        Entity* e = NULL;
1004        std::vector<Entity*>::iterator entityIterator = entities.begin();
1005        while(entityIterator != entities.end())
1006        {
1007                uptonowSurfaceArea += (*entityIterator)->getSurfaceArea();
1008                if(uptonowSurfaceArea >= randa)
1009                {
1010                        e = *entityIterator;
1011                        break;
1012                }
1013                entityIterator++;
1014        }
1015
1016        const Material* m = e->sampleSurface(starter);
1017
1018        float surfa = starter.radiance.z;
1019
1020        Vector rtexc = starter.radiance;
1021        starter.radiance = m->getTextureDiffuseBrdf(rtexc);
1022        starter.radiance *= sumSurfaceArea / NRADIONS;
1023        starter.probability = (float)NRADIONS / (entities.size() * surfa );
1024}
1025
1026void PathMapEffect::uploadRadions()
1027{
1028        int nRadions = bushStarters.size();
1029        struct TMR{
1030                float pos[4];
1031                float dir[4];
1032//              float pow[4];
1033        };
1034        TMR* tm = new TMR[nRadions];
1035        for(int i=0; i<nRadions; i++)
1036        {
1037//*
1038                tm[i].pos[0] = bushStarters[i].position[0];
1039                tm[i].pos[1] = bushStarters[i].position[1];
1040                tm[i].pos[2] = bushStarters[i].position[2];
1041                tm[i].pos[3] = 1.0;
1042                tm[i].dir[0] = bushStarters[i].normal[0];
1043                tm[i].dir[1] = bushStarters[i].normal[1];
1044                tm[i].dir[2] = bushStarters[i].normal[2];
1045                tm[i].dir[3] = 1.0;
1046//              tm[i].pow[0] = bushStarters[i].radiance[0];
1047//              tm[i].pow[1] = bushStarters[i].radiance[1];
1048//              tm[i].pow[2] = bushStarters[i].radiance[2];
1049//              tm[i].pow[3] = 1.0;
1050/*/
1051                tm[i].pos[0] = 0.9;
1052                tm[i].pos[1] = 0.2;
1053                tm[i].pos[2] = 0.2;
1054                tm[i].pos[3] = 1.0;
1055                tm[i].dir[0] = 0.2;
1056                tm[i].dir[1] = 0.9;
1057                tm[i].dir[2] = 0.2;
1058                tm[i].dir[3] = 1.0;
1059                tm[i].pow[0] = 0.2;
1060                tm[i].pow[1] = 0.2;
1061                tm[i].pow[2] = 0.9;     //blue
1062                tm[i].pow[3] = 0.99;
1063//*/
1064        }
1065
1066        RECT imgSize;
1067        imgSize.top = imgSize.left = 0;
1068        imgSize.bottom =  nRadions;
1069        imgSize.right = 2 * nRadions / 4096;
1070        D3DXLoadSurfaceFromMemory(radionSurface, NULL, NULL, tm, D3DFMT_A32B32G32R32F,
1071                imgSize.right * 4 * sizeof(float), NULL, &imgSize, D3DX_FILTER_NONE, 0);
1072
1073        delete [] tm;
1074}
1075
1076void PathMapEffect::fillRadionPosArray(void* pData)
1077{
1078        int nRadions = NRADIONS;
1079        struct TMR{
1080                float pos[3];
1081                float rad[3];
1082        };
1083        TMR* tm = (TMR*)pData;
1084        for(int i=0; i<nRadions; i++)
1085        {
1086                tm[i].pos[0] = bushStarters[i].position[0];
1087                tm[i].pos[1] = bushStarters[i].position[1];
1088                tm[i].pos[2] = bushStarters[i].position[2];
1089                tm[i].rad[0] = bushStarters[i].radiance[0];
1090                tm[i].rad[1] = bushStarters[i].radiance[1];
1091                tm[i].rad[2] = bushStarters[i].radiance[2];
1092        }
1093}
1094
1095const wchar_t* PathMapEffect::getWeightsString()
1096{
1097        static wchar_t ws[512];
1098        ws[0] = 0;
1099        char wan[64];
1100        float sumw = 0.0f;
1101        for(int i=0; i<33; i++)
1102        {
1103//              StrCpy(wan, L"%f ");
1104                if(i == 32)
1105                        sprintf(wan, "%.3f ", (double)sumw);
1106                else
1107                {
1108                        sumw += weights[i];
1109                        sprintf(wan, "%.3f ", (double)weights[i]);
1110                }
1111                wchar_t* wideValue = new wchar_t[MultiByteToWideChar(CP_ACP, 0, wan, -1, NULL, 0)];
1112                MultiByteToWideChar(CP_ACP, 0, wan, -1, wideValue, 511);
1113                StrCatW(ws, wideValue);
1114                delete wideValue;
1115        }
1116        return ws;
1117}
1118
1119
1120void PathMapEffect::savePathMaps()
1121{
1122//      std::fstream entryPointFile("prm\\prmEntryPoints.dat", std::ios::out | std::ios::binary);
1123        char eFileName[512];
1124        sprintf(eFileName, "%s\\prmEntryPoints.text", LC::c-this->prmDirectory);
1125        std::fstream entryPointFile(eFileName, std::ios::out);
1126
1127        entryPointFile << "nEntryPoints ";
1128        entryPointFile << NRADIONS;
1129        entryPointFile << "\n";
1130
1131        for(unsigned int u=0; u < NRADIONS; u++)
1132        {
1133                entryPointFile << bushStarters.at(u);
1134                entryPointFile << "\n";
1135        }
1136
1137        entryPointFile << "Clusters ";
1138        entryPointFile << NCLUSTERS;
1139        entryPointFile << "\n";
1140
1141        for(unsigned int c=0; c < NCLUSTERS; c++)
1142        {
1143//              entryPointFile.write((char*)&clusterLenghts[c], sizeof(unsigned int));
1144                entryPointFile << clusterLenghts[c] << '\n';
1145        }
1146        entryPointFile << "\n";
1147
1148        entryPointFile.flush();
1149        entryPointFile.close();
1150
1151        unsigned int iEntity = 0;
1152        std::vector<Entity*>::iterator entityIterator = entities.begin();
1153        while(entityIterator != entities.end())
1154        {
1155                (*entityIterator)->savePRM();
1156
1157                entityIterator++;
1158                iEntity++;
1159        }
1160}
1161
1162void PathMapEffect::loadPathMaps()
1163{
1164/*      std::fstream entryPointFile("prm\\prmEntryPoints.dat", std::ios::in | std::ios::binary);
1165
1166        bushStarters.clear();
1167
1168        for(unsigned int u=0; u < NRADIONS; u++)
1169        {
1170                Radion ri;
1171                entryPointFile >> ri;
1172                bushStarters.push_back(ri);
1173        }
1174       
1175        for(unsigned int c=0; c < NCLUSTERS; c++)
1176        {
1177                entryPointFile.read((char*)&clusterLenghts[c], sizeof(unsigned int));
1178        }
1179
1180        entryPointFile.close();*/
1181        char eFileName[512];
1182        sprintf(eFileName, "%s\\prmEntryPoints.text", LC::c-this->prmDirectory);
1183
1184        std::fstream entryPointFile(eFileName, std::ios::in);
1185
1186        char keyword[256];
1187
1188        unsigned int redrad;
1189        entryPointFile >> keyword;      //nradions
1190        entryPointFile >> redrad;
1191
1192        bushStarters.clear();
1193   
1194        for(unsigned int u=0; u < NRADIONS; u++)
1195        {
1196                Radion ri;
1197                entryPointFile >> ri;
1198                bushStarters.push_back(ri);
1199        }
1200
1201        entryPointFile >> keyword; //ncluster
1202        entryPointFile >> redrad;
1203       
1204        for(unsigned int c=0; c < NCLUSTERS; c++)
1205        {
1206                entryPointFile >> clusterLenghts[c];
1207        }
1208
1209        entryPointFile.close();
1210
1211        srand(0xef23ab32);
1212        unsigned int iEntity = 0;
1213        std::vector<Entity*>::iterator entityIterator = entities.begin();
1214        while(entityIterator != entities.end())
1215        {
1216                (*entityIterator)->findNearClusters(bushStarters, NCLUSTERS);
1217                (*entityIterator)->loadPRM();
1218
1219                entityIterator++;
1220                iEntity++;
1221        }
1222}
1223
1224void PathMapEffect::loadScene(const char* sceneFileName)
1225{
1226        std::fstream sceneFile(sceneFileName, std::ios::in);
1227
1228        char keyword[256];
1229        while(!sceneFile.eof())
1230        {
1231                sceneFile >> keyword;
1232                if(strcmp(keyword, "mesh") == 0)
1233                {
1234                        int meshAtlasSize = 128;
1235                        bool needsUV = true;
1236                        bool needsTBN = false;
1237                        int dividePcs = 1;
1238                        char meshname[256];
1239                        wchar_t* wide = NULL;
1240                        wchar_t* wideXML = NULL;
1241                        wchar_t* wideOgre = NULL;
1242                        Vector color = Vector::RGBWHITE;
1243
1244                        sceneFile >> meshname;
1245                        if(strcmp(meshname, "{") == 0)
1246                                strcpy(meshname, "mesh");
1247                        while(strcmp(keyword, "}") != 0 && !sceneFile.eof())
1248                        {
1249                                sceneFile >> keyword;
1250                                if(strcmp(keyword, "xfile") == 0)
1251                                {
1252                                        sceneFile >> keyword;
1253                                        if(keyword)
1254                                        {
1255                                                wide = L::clone(keyword);
1256                                        }
1257                                }
1258                                if(strcmp(keyword, "ogreXMLfile") == 0)
1259                                {
1260                                        sceneFile >> keyword;
1261                                        if(keyword)
1262                                        {
1263                                                wideXML = L::clone(keyword);
1264                                        }
1265                                }
1266                                if(strcmp(keyword, "ogrefile") == 0)
1267                                {
1268                                        sceneFile >> keyword;
1269                                        if(keyword)
1270                                        {
1271                                                wideOgre = L::clone(keyword);
1272                                        }
1273                                }
1274                                if(strcmp(keyword, "pathmapresolution") == 0)
1275                                {
1276                                        sceneFile >> meshAtlasSize;
1277                                }
1278                                if(strcmp(keyword, "divide") == 0)
1279                                {
1280                                        sceneFile >> dividePcs;
1281                                }
1282                        }
1283                        if(wideXML)
1284                        {
1285                                loadMesh(Mesh::OgreXMLMesh, wideXML, wideOgre, meshAtlasSize, meshname, dividePcs, needsUV, needsTBN);
1286                                delete [] wideXML;
1287                        }
1288                        else if(wide)
1289                        {
1290                                loadMesh(Mesh::DirectXMesh, wide, wideOgre, meshAtlasSize, meshname, dividePcs, needsUV, needsTBN);
1291                                delete [] wide;
1292                        }
1293                        else
1294                        if(wideOgre)
1295                                delete [] wideOgre;
1296                }
1297
1298                if(strcmp(keyword, "entity") == 0)
1299                {
1300                        char entityName[256];
1301                        char prmFileName[256];
1302                        Mesh* baseMesh = NULL;
1303                        D3DXMATRIX trafo;
1304                        D3DXMatrixIdentity(&trafo);
1305                        int nNearClusters = 16;
1306
1307                        sceneFile >> entityName;
1308                        if(strcmp(entityName, "{") == 0)
1309                                strcpy(entityName, "noname");
1310
1311                        while(strcmp(keyword, "}") != 0 && !sceneFile.eof())
1312                        {
1313                                sceneFile >> keyword;
1314                                if(strcmp(keyword, "pathmapfile") == 0)
1315                                {
1316                                        sceneFile >> keyword;
1317                                        strcpy(prmFileName, keyword);
1318                                }
1319                                if(strcmp(keyword, "mesh") == 0)
1320                                {
1321                                        sceneFile >> keyword;
1322
1323                                        std::vector<Mesh*>::iterator i = meshes.begin();
1324                                        while(i != meshes.end())
1325                                        {
1326                                                if(strcmp((*i)->getName(), keyword) == 0)
1327                                                {
1328                                                        baseMesh = *i;
1329                                                        break;
1330                                                }
1331                                                i++;
1332                                        }
1333                                }
1334                                if(strcmp(keyword, "transformation") == 0)
1335                                {
1336                                        for(int i=0; i<16; i++)
1337                                                sceneFile >> trafo.m[i%4][i/4];
1338                                }
1339                                if(strcmp(keyword, "pathmapclusters") == 0)
1340                                {
1341                                        sceneFile >> nNearClusters;
1342                                }
1343                        }
1344                        if(baseMesh)
1345                        {
1346                                Entity* e = new Entity(baseMesh, entityName, prmFileName, trafo, nNearClusters);
1347                                entities.push_back(e);
1348                        }
1349                }
1350        }
1351        sceneFile.close();
1352}
1353
1354
1355void PathMapEffect::renderScene(const RenderStrategy& renderStrategy)
1356{
1357        renderStrategy.applyTargets();
1358
1359        renderStrategy.applyRenderState();
1360
1361        if( SUCCEEDED( device->BeginScene() ) )
1362        {
1363                renderStrategy.applyTechnique();
1364                UINT nPasses;
1365                effect->Begin( &nPasses, 0 );
1366                for(UINT j=0;j<nPasses;j++)
1367                {
1368                        effect->BeginPass(j);
1369
1370                        //loop through all entities
1371                        std::vector<Entity*>::iterator entityIterator = entities.begin();
1372                        while(entityIterator != entities.end())
1373                        {
1374
1375                                (*entityIterator)->drawAllSubEntities(renderStrategy);
1376                                entityIterator++;
1377                        }
1378
1379                        effect->EndPass();
1380                }
1381                effect->End();
1382                device->EndScene();
1383        }
1384
1385        renderStrategy.resetRenderState();
1386
1387}
1388
1389void PathMapEffect::saveScene(const char* sceneFileName)
1390{
1391        std::ofstream psf(sceneFileName);
1392       
1393        std::vector<Mesh*>::iterator iMesh = meshes.begin();
1394        while(iMesh != meshes.end())
1395        {
1396                (*iMesh)->saveSceneInfo(psf);
1397                iMesh++;
1398        }
1399
1400        std::vector<Entity*>::iterator iEntity = entities.begin();
1401        while(iEntity != entities.end())
1402        {
1403                (*iEntity)->saveSceneInfo(psf);
1404                iEntity++;
1405        }
1406}
1407
1408const wchar_t* PathMapEffect::getCurrentMethodName()
1409{
1410        int lmode = parameters->GetInt(fIndirectLightingMode);
1411        if(lmode == 3)
1412                return L"PRM only";
1413        if(lmode == 2)
1414                return L"direct + PRM";
1415        if(lmode == 1)
1416                return L"direct + ambient";
1417        if(lmode == 0)
1418                return L"direct only";
1419}
Note: See TracBrowser for help on using the repository browser.