khanat-opennel-code/code/nel/tools/3d/plugin_max/nel_patch_paint/paint_data.cpp
2010-05-06 02:08:41 +02:00

340 lines
8.1 KiB
C++

#include "stdafx.h"
#include "nel_patch_paint.h"
#include "nel/misc/time_nl.h"
using namespace NLMISC;
// ------------------------------------------------------------------------------------------------------------------------------------------------------
#define DBGWELD_DUMPx
#define DBGWELD_ACTIONx
#define DBG_NAMEDSELSx
// ------------------------------------------------------------------------------------------------------------------------------------------------------
class FinalPatchRestore : public RestoreObj
{
public:
BOOL gotRedo;
PatchMesh undo;
PatchMesh redo;
PatchMesh *patch;
RPatchMesh *rundo;
RPatchMesh *rredo;
RPatchMesh *rpatch;
FinalPatchRestore(PatchMesh *s, RPatchMesh *rs)
{
rundo = NULL;
rredo = NULL;
undo = *s;
if (rs)
{
rundo=new RPatchMesh();
*rundo = *rs;
}
patch = s;
rpatch = rs;
gotRedo = FALSE;
}
virtual ~FinalPatchRestore()
{
if (rundo)
delete rundo;
if (rredo)
delete rredo;
}
void Restore(int isUndo)
{
if (!gotRedo)
{
gotRedo = TRUE;
redo = *patch;
if (rpatch)
{
if (rredo==NULL)
rredo=new RPatchMesh();
*rredo = *rpatch;
}
}
*patch = undo;
if (rundo)
*rpatch = *rundo;
}
void Redo()
{
*patch = redo;
if (rredo)
*rpatch = *rredo;
}
int Size() { return 1; }
void EndHold() { }
TSTR Description() { return TSTR(_T("FinalPatchRestore")); }
};
// ------------------------------------------------------------------------------------------------------------------------------------------------------
PaintPatchData::PaintPatchData (PaintPatchMod *mod)
{
flags = 0;
tempData = NULL;
preloadTiles = mod->preloadTiles;
}
PaintPatchData::PaintPatchData (PaintPatchData& emc)
{
flags = emc.flags;
tempData = NULL;
finalPatch = emc.finalPatch;
rfinalPatch = emc.rfinalPatch;
preloadTiles = emc.preloadTiles;
}
void PaintPatchData::Apply(TimeValue t, RPO *patchOb, int selLevel)
{
TTicks ticks=CTime::getPerformanceTime ();
// Either just copy it from the existing cache or rebuild from previous level!
if (!GetFlag(EPD_UPDATING_CACHE) && tempData
&& tempData->PatchCached(t))
{
RPatchMesh *rpatch;
PatchMesh *patch=tempData->GetPatch(t, rpatch);
patchOb->patch.DeepCopy( patch,
PART_GEOM | SELECT_CHANNEL | PART_SUBSEL_TYPE|
PART_DISPLAY | PART_TOPO | TEXMAP_CHANNEL);
//rpatch->UpdateBinding (*patch, t);
*patchOb->rpatch=*rpatch;
patchOb->PointsWereChanged();
}
else if (GetFlag(EPD_HASDATA))
{
int count = changes.Count();
if (count)
{
finalPatch = patchOb->patch;
rfinalPatch = *patchOb->rpatch;
for (int i = 0; i < count; ++i)
{
PModRecord *rec = changes[i];
// Record the topo flags
RecordTopologyTags(&patchOb->patch);
BOOL result = rec->Redo(&patchOb->patch, patchOb->rpatch, 0);
UpdateChanges(&patchOb->patch, patchOb->rpatch);
// If we hit one that didn't play back OK, we need to flush the remainder
if (!result)
{
for (int j = i; j < count; ++j)
delete changes[j];
changes.Delete(i, count - i);
break;
}
}
// Nuke the changes table
count = changes.Count();
for (int k = 0; k < count; ++k)
delete changes[k];
changes.Delete(0, count);
changes.Shrink();
count = 0;
}
else
{
// Apply deltas to incoming shape, placing into finalPatch
patchOb->patch = finalPatch;
*patchOb->rpatch = rfinalPatch;
}
patchOb->PointsWereChanged();
// Kind of a waste when there's no animation...
patchOb->UpdateValidity(GEOM_CHAN_NUM, FOREVER);
patchOb->UpdateValidity(TOPO_CHAN_NUM, FOREVER);
patchOb->UpdateValidity(SELECT_CHAN_NUM, FOREVER);
patchOb->UpdateValidity(SUBSEL_TYPE_CHAN_NUM, FOREVER);
patchOb->UpdateValidity(DISP_ATTRIB_CHAN_NUM, FOREVER);
}
else
{
finalPatch = patchOb->patch;
rfinalPatch = *patchOb->rpatch;
}
patchOb->patch.dispFlags = 0;
if (GetFlag(EPD_UPDATING_CACHE))
{
nlassert(tempData);
tempData->UpdateCache(patchOb);
SetFlag(EPD_UPDATING_CACHE, FALSE);
}
ticks=CTime::getPerformanceTime ()-ticks;
nldebug ("%f", CTime::ticksToSecond(ticks));
}
void PaintPatchData::Invalidate(PartID part, BOOL patchValid)
{
if (tempData)
{
tempData->Invalidate(part, patchValid);
}
}
void PaintPatchData::BeginEdit(TimeValue t)
{
nlassert(tempData);
if (!GetFlag(EPD_HASDATA))
SetFlag(EPD_HASDATA, TRUE);
}
EPTempData *PaintPatchData::TempData(PaintPatchMod *mod)
{
if (!tempData)
{
nlassert(mod->ip);
tempData = new EPTempData(mod, this);
}
return tempData;
}
void PaintPatchData::RescaleWorldUnits(float f)
{
// Now rescale stuff inside our data structures
Matrix3 stm = ScaleMatrix(Point3(f, f, f));
finalPatch.Transform(stm);
}
void PaintPatchData::RecordTopologyTags(PatchMesh *patch)
{
// First, stuff all -1's into aux fields
int i;
for (i = 0; i < patch->numVerts; ++i)
patch->verts[i].aux1 = 0xffffffff;
for (i = 0; i < patch->numVecs; ++i)
patch->vecs[i].aux1 = 0xffffffff;
for (i = 0; i < patch->numPatches; ++i)
patch->patches[i].aux1 = 0xffffffff;
}
void PaintPatchData::UpdateChanges(PatchMesh *patch, RPatchMesh *rpatch, BOOL checkTopology)
{
if (theHold.Holding())
{
//theHold.Put(new FinalPatchRestore(&finalPatch, &rfinalPatch));
if (rpatch)
theHold.Put(new FinalPatchRestore(&finalPatch, &rfinalPatch));
else
theHold.Put(new FinalPatchRestore(&finalPatch, NULL));
}
// Store the final shape
finalPatch = *patch;
if (rpatch)
rfinalPatch = *rpatch;
}
#define EPD_GENERAL_CHUNK 0x1000 // Obsolete as of 11/12/98 (r3)
#define CHANGE_CHUNK 0x1010 // Obsolete as of 11/12/98 (r3)
#define EPD_R3_GENERAL_CHUNK 0x1015
#define MESH_ATTRIB_CHUNK 0x1020
#define DISP_PARTS_CHUNK 0x1030
#define VTESS_ATTRIB_CHUNK 0x1070
#define PTESS_ATTRIB_CHUNK 0x1080
#define DTESS_ATTRIB_CHUNK 0x1090
#define NORMAL_TESS_ATTRIB_CHUNK 0x1110
#define WELD_TESS_ATTRIB_CHUNK 0x1120
#define VERTMAP_CHUNK 0x1130
#define FINALPATCH_CHUNK 0x1140
#define RENDERSTEPS_CHUNK 0x1150
#define SHOWINTERIOR_CHUNK 0x1160
// Named sel set chunks
#define VSELSET_CHUNK 0x1040
#define ESELSET_CHUNK 0x1050
#define PSELSET_CHUNK 0x1060
#define RPO_MODE_TILE 0x4000
#define RFINALPATCH_CHUNK 0x4001
#define RPO_MODE_TILE_TRANSITION 0x4002
#define RPO_INCLUDE_MESHES 0x4003
#define RPO_PRELOAD_TILES 0x4010
IOResult PaintPatchData::Save(ISave *isave)
{
ULONG nb;
isave->BeginChunk(EPD_R3_GENERAL_CHUNK);
isave->Write(&flags, sizeof(DWORD), &nb);
isave->EndChunk();
isave->BeginChunk(FINALPATCH_CHUNK);
finalPatch.Save(isave);
isave->EndChunk();
isave->BeginChunk(RFINALPATCH_CHUNK);
rfinalPatch.Save(isave);
isave->EndChunk();
isave->BeginChunk(RPO_INCLUDE_MESHES);
isave->Write(&includeMeshes, sizeof(includeMeshes), &nb);
isave->EndChunk();
isave->BeginChunk(RPO_PRELOAD_TILES);
isave->Write(&preloadTiles, sizeof(preloadTiles), &nb);
isave->EndChunk();
return IO_OK;
}
IOResult PaintPatchData::Load(ILoad *iload)
{
IOResult res;
ULONG nb;
PModRecord *theChange;
while (IO_OK == (res = iload->OpenChunk()))
{
switch (iload->CurChunkID())
{
// The following code is here to load pre-release 3 files.
case EPD_GENERAL_CHUNK:
iload->SetObsolete();
iload->Read(&flags, sizeof(DWORD), &nb);
break;
case PATCHCHANGERECORD_CHUNK:
theChange = new PatchChangeRecord;
goto load_change;
load_change:
//
// The following code is used for post-release 3 files
//
case EPD_R3_GENERAL_CHUNK:
res = iload->Read(&flags, sizeof(DWORD), &nb);
break;
case FINALPATCH_CHUNK:
res = finalPatch.Load(iload);
break;
case RFINALPATCH_CHUNK:
res = rfinalPatch.Load(iload);
break;
case RPO_INCLUDE_MESHES:
res = iload->Read(&includeMeshes, sizeof(includeMeshes), &nb);
break;
case RPO_PRELOAD_TILES:
res = iload->Read(&preloadTiles, sizeof(preloadTiles), &nb);
break;
}
iload->CloseChunk();
if (res != IO_OK)
return res;
}
return IO_OK;
}