340 lines
7.8 KiB
C++
340 lines
7.8 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;
|
|
}
|