Files
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
2026-06-24 21:28:16 -05:00

1918 lines
47 KiB
C++

/**********************************************************************
*<
FILE: mapmod.cpp
DESCRIPTION: A UVW mapping modifier 6/1/98 Copied over to make it work
in my code. JLC
CREATED BY: Rolf Berteig
HISTORY: 10/21/95
*> Copyright (c) 1994, All Rights Reserved.
**********************************************************************/
#include "mods.h"
#include "iparamm.h"
#include "texutil.h"
#include "bmmlib.h"
#include "simpobj.h"
#include "simpmod.h"
#include "decomp.h"
#include "mapping.h"
#include "buildver.h"
class MapMod : public MappingMod {
public:
IParamBlock *pblock;
static IParamMap *pmapParam;
static MoveModBoxCMode *moveMode;
static RotateModBoxCMode *rotMode;
static UScaleModBoxCMode *uscaleMode;
static NUScaleModBoxCMode *nuscaleMode;
static SquashModBoxCMode *squashMode;
static FaceAlignMode *faceAlignMode;
static RegionFitMode *regionFitMode;
static PickAcquire pickAcquire;
static MapMod *editMod;
MapMod(BOOL create);
// From Animatable
void DeleteThis() { delete this; }
void GetClassName(TSTR& s) {s=GetString(IDS_RB_MAPMOD);}
virtual Class_ID ClassID() {return Class_ID(UVWMAPOSM_CLASS_ID,0);}
void BeginEditParams( IObjParam *ip, ULONG flags,Animatable *prev);
void EndEditParams( IObjParam *ip,ULONG flags,Animatable *next);
TCHAR *GetObjectName() { return GetString(IDS_RB_UVWMAPPING); }
CreateMouseCallBack* GetCreateMouseCallBack() {return NULL;}
BOOL AssignController(Animatable *control,int subAnim);
int SubNumToRefNum(int subNum);
ChannelMask ChannelsUsed() {return PART_GEOM|PART_TOPO|PART_SELECT|PART_SUBSEL_TYPE|PART_VERTCOLOR;}
ChannelMask ChannelsChanged() {return TEXMAP_CHANNEL|PART_VERTCOLOR; }
Class_ID InputType() {return mapObjectClassID;}
void ModifyObject(TimeValue t, ModContext &mc, ObjectState *os, INode *node);
Interval LocalValidity(TimeValue t);
IOResult Load(ILoad *iload);
IOResult Save(ISave *isave);
int NumRefs() {return 2;}
RefTargetHandle GetReference(int i);
void SetReference(int i, RefTargetHandle rtarg);
int NumSubs() {return 2;}
Animatable* SubAnim(int i);
TSTR SubAnimName(int i);
RefTargetHandle Clone(RemapDir& remap = NoRemap());
RefResult NotifyRefChanged(Interval changeInt, RefTargetHandle hTarget, PartID& partID, RefMessage message);
void ActivateSubobjSel(int level, XFormModes& modes);
// From MappingMod
void EnterNormalAlign();
void ExitNormalAlign();
void EnterRegionFit();
void ExitRegionFit();
int GetMapType();
void SetMapType(int type);
float GetTile(TimeValue t,int which);
void SetTile(TimeValue t,int which, float tile);
BOOL GetFlip(int which);
void SetFlip(int which,BOOL flip);
void EnterAcquire();
void ExitAcquire();
float GetLength(TimeValue t);
float GetWidth(TimeValue t);
float GetHeight(TimeValue t);
int GetAxis();
void SetLength(TimeValue t,float v);
void SetWidth(TimeValue t,float v);
void SetHeight(TimeValue t,float v);
void SetAxis(int v);
int GetFirstParamVer() {return 3;}
int GetPBlockVersion() {return pblock->GetVersion();}
};
//--- ClassDescriptor and class vars ---------------------------------
IObjParam* MappingMod::ip = NULL;
IParamMap* MapMod::pmapParam = NULL;
MoveModBoxCMode* MapMod::moveMode = NULL;
RotateModBoxCMode* MapMod::rotMode = NULL;
UScaleModBoxCMode* MapMod::uscaleMode = NULL;
NUScaleModBoxCMode* MapMod::nuscaleMode = NULL;
SquashModBoxCMode* MapMod::squashMode = NULL;
FaceAlignMode* MapMod::faceAlignMode = NULL;
RegionFitMode* MapMod::regionFitMode = NULL;
PickAcquire MapMod::pickAcquire;
MapMod* MapMod::editMod = NULL;
class UVWMapClassDesc:public ClassDesc {
public:
int IsPublic() { return 1; }
void * Create(BOOL loading = FALSE) {return new MapMod(!loading);}
const TCHAR * ClassName() { return GetString(IDS_RB_UVWMAP_CLASS); }
SClass_ID SuperClassID() { return OSM_CLASS_ID; }
Class_ID ClassID() { return Class_ID(UVWMAPOSM_CLASS_ID,0); }
const TCHAR* Category() {return GetString(IDS_RB_DEFSURFACE);}
};
static UVWMapClassDesc mapDesc;
extern ClassDesc* GetUVWMapModDesc() {return &mapDesc;}
static void DoBoxIcon(BOOL sel,float length, PolyLineProc& lp);
//--- Parameter map/block descriptors -------------------------------
#define PB_MAPTYPE 0
#define PB_UTILE 1
#define PB_VTILE 2
#define PB_WTILE 3
#define PB_UFLIP 4
#define PB_VFLIP 5
#define PB_WFLIP 6
#define PB_CAP 7
#define PB_CHANNEL 8
#define PB_LENGTH 9
#define PB_WIDTH 10
#define PB_HEIGHT 11
#define PB_AXIS 12
//
//
// Parameters
static int mapIDs[] = {IDC_MAP_PLANAR,IDC_MAP_CYL,IDC_MAP_SPHERE,IDC_MAP_BALL,IDC_MAP_BOX,IDC_MAP_FACE};
static int chanIDs[] = {IDC_MAP_CHAN1,IDC_MAP_CHAN2};
static int axisIDs[] = {IDC_MAP_X,IDC_MAP_Y,IDC_MAP_Z};
static ParamUIDesc descParam[] = {
// Map type
ParamUIDesc(PB_MAPTYPE,TYPE_RADIO,mapIDs,6),
// U Tile
ParamUIDesc(
PB_UTILE,
EDITTYPE_FLOAT,
IDC_MAP_UTILE,IDC_MAP_UTILESPIN,
-999999999.0f,999999999.0f,
0.01f),
// V Tile
ParamUIDesc(
PB_VTILE,
EDITTYPE_FLOAT,
IDC_MAP_VTILE,IDC_MAP_VTILESPIN,
-999999999.0f,999999999.0f,
0.01f),
// W Tile
ParamUIDesc(
PB_WTILE,
EDITTYPE_FLOAT,
IDC_MAP_WTILE,IDC_MAP_WTILESPIN,
-999999999.0f,999999999.0f,
0.01f),
// U Flip
ParamUIDesc(PB_UFLIP,TYPE_SINGLECHEKBOX,IDC_MAP_UFLIP),
// V Flip
ParamUIDesc(PB_VFLIP,TYPE_SINGLECHEKBOX,IDC_MAP_VFLIP),
// W Flip
ParamUIDesc(PB_WFLIP,TYPE_SINGLECHEKBOX,IDC_MAP_WFLIP),
// Cap
ParamUIDesc(PB_CAP,TYPE_SINGLECHEKBOX,IDC_MAP_CAP),
// Channel
ParamUIDesc(PB_CHANNEL,TYPE_RADIO,chanIDs,2),
// Length
ParamUIDesc(
PB_LENGTH,
EDITTYPE_UNIVERSE,
IDC_MAP_LENGTH,IDC_MAP_LENGTHSPIN,
-999999999.0f,999999999.0f,
SPIN_AUTOSCALE),
// Width
ParamUIDesc(
PB_WIDTH,
EDITTYPE_UNIVERSE,
IDC_MAP_WIDTH,IDC_MAP_WIDTHSPIN,
-999999999.0f,999999999.0f,
SPIN_AUTOSCALE),
// Height
ParamUIDesc(
PB_HEIGHT,
EDITTYPE_UNIVERSE,
IDC_MAP_HEIGHT,IDC_MAP_HEIGHTSPIN,
-999999999.0f,999999999.0f,
SPIN_AUTOSCALE),
// Axis
ParamUIDesc(PB_AXIS,TYPE_RADIO,axisIDs,3),
};
#define PARAMDESC_LENGH 13
static ParamBlockDescID descVer0[] = {
{ TYPE_INT, NULL, FALSE, 0 },
{ TYPE_FLOAT, NULL, TRUE, 1 },
{ TYPE_FLOAT, NULL, TRUE, 2 },
{ TYPE_FLOAT, NULL, TRUE, 3 },
{ TYPE_INT, NULL, TRUE, 4 },
{ TYPE_INT, NULL, TRUE, 5 },
{ TYPE_INT, NULL, TRUE, 6 }};
static ParamBlockDescID descVer1[] = {
{ TYPE_INT, NULL, FALSE, 0 },
{ TYPE_FLOAT, NULL, TRUE, 1 },
{ TYPE_FLOAT, NULL, TRUE, 2 },
{ TYPE_FLOAT, NULL, TRUE, 3 },
{ TYPE_INT, NULL, FALSE, 4 },
{ TYPE_INT, NULL, FALSE, 5 },
{ TYPE_INT, NULL, FALSE, 6 },
{ TYPE_INT, NULL, FALSE, 7 }};
static ParamBlockDescID descVer2[] = {
{ TYPE_INT, NULL, FALSE, 0 },
{ TYPE_FLOAT, NULL, TRUE, 1 },
{ TYPE_FLOAT, NULL, TRUE, 2 },
{ TYPE_FLOAT, NULL, TRUE, 3 },
{ TYPE_INT, NULL, FALSE, 4 },
{ TYPE_INT, NULL, FALSE, 5 },
{ TYPE_INT, NULL, FALSE, 6 },
{ TYPE_INT, NULL, FALSE, 7 },
{ TYPE_INT, NULL, FALSE, 8 }};
static ParamBlockDescID descVer3[] = {
{ TYPE_INT, NULL, FALSE, 0 },
{ TYPE_FLOAT, NULL, TRUE, 1 },
{ TYPE_FLOAT, NULL, TRUE, 2 },
{ TYPE_FLOAT, NULL, TRUE, 3 },
{ TYPE_INT, NULL, FALSE, 4 },
{ TYPE_INT, NULL, FALSE, 5 },
{ TYPE_INT, NULL, FALSE, 6 },
{ TYPE_INT, NULL, FALSE, 7 },
{ TYPE_INT, NULL, FALSE, 8 },
{ TYPE_FLOAT, NULL, TRUE, 9 },
{ TYPE_FLOAT, NULL, TRUE, 10 },
{ TYPE_FLOAT, NULL, TRUE, 11 },
{ TYPE_INT, NULL, FALSE, 12 },
};
#define PBLOCK_LENGTH 13
// Array of old versions
static ParamVersionDesc versions[] = {
ParamVersionDesc(descVer0,7,0),
ParamVersionDesc(descVer1,8,1),
ParamVersionDesc(descVer2,9,2),
};
#define NUM_OLDVERSIONS 3
// Current version
#define CURRENT_VERSION 3
static ParamVersionDesc curVersion(descVer3,PBLOCK_LENGTH,CURRENT_VERSION);
//--- MapDlgProc -------------------------------------------------------
void MappingMod::ViewportAlign()
{
ViewExp *vpt = ip->GetActiveViewport();
if (!vpt) return;
// Get mod contexts and nodes for this modifier
ModContextList mcList;
INodeTab nodeList;
ip->GetModContexts(mcList,nodeList);
// Viewport tm
Matrix3 vtm;
vpt->GetAffineTM(vtm);
vtm = Inverse(vtm);
// Node tm
Matrix3 ntm = nodeList[0]->GetObjectTM(ip->GetTime());
ntm.NoScale();
// MC tm
Matrix3 mctm(1);
if (mcList[0]->tm) mctm = *mcList[0]->tm;
// Compute the new destination transform for tmCont
Matrix3 destTM = vtm * Inverse(ntm) * mctm;
destTM.PreRotateZ(PI);
switch (GetAxis()) {
case 0:
destTM.PreRotateY(-HALFPI);
break;
case 1:
destTM.PreRotateX(HALFPI);
break;
}
// Current val of tmCont
Matrix3 curTM(1);
tmControl->GetValue(ip->GetTime(),&curTM,FOREVER,CTRL_RELATIVE);
Point3 s;
for (int i=0; i<3; i++) s[i] = Length(curTM.GetRow(i));
// These types are aligned differently
if (GetMapType()==MAP_CYLINDRICAL ||
GetMapType()==MAP_SPHERICAL ||
GetMapType()==MAP_BALL) {
destTM.PreRotateX(-HALFPI);
}
// Keep position and scale the same
destTM.SetTrans(curTM.GetTrans());
destTM.PreScale(s);
// Plug-in the new value
SetXFormPacket pckt(destTM);
tmControl->SetValue(ip->GetTime(), &pckt);
nodeList.DisposeTemporary();
ip->ReleaseViewport(vpt);
ip->RedrawViews(ip->GetTime());
}
static void MatrixFromNormal(Point3& normal, Matrix3& mat)
{
Point3 vx;
vx.z = .0f;
vx.x = -normal.y;
vx.y = normal.x;
if ( vx.x == .0f && vx.y == .0f ) {
vx.x = 1.0f;
}
mat.SetRow(0,vx);
mat.SetRow(1,normal^vx);
mat.SetRow(2,normal);
mat.SetTrans(Point3(0,0,0));
mat.NoScale();
}
void FaceAlignMouseProc::FaceAlignMap(HWND hWnd,IPoint2 m)
{
ViewExp *vpt = ip->GetViewport(hWnd);
if (!vpt) return;
Ray ray, wray;
float at;
TimeValue t = ip->GetTime();
GeomObject *obj;
Point3 norm, pt;
Interval valid;
// Get mod contexts and nodes for this modifier
ModContextList mcList;
INodeTab nodeList;
ip->GetModContexts(mcList,nodeList);
// Calculate a ray from the mouse point
vpt->MapScreenToWorldRay(float(m.x), float(m.y),wray);
for (int i=0; i<nodeList.Count(); i++) {
INode *node = nodeList[i];
// Get the object from the node
ObjectState os = node->EvalWorldState(t);
if (os.obj->SuperClassID()==GEOMOBJECT_CLASS_ID) {
obj = (GeomObject*)os.obj;
} else {
continue;
}
// Back transform the ray into object space.
Matrix3 obtm = node->GetObjectTM(t);
Matrix3 iobtm = Inverse(obtm);
ray.p = iobtm * wray.p;
ray.dir = VectorTransform(iobtm, wray.dir);
// See if we hit the object
if (obj->IntersectRay(t,ray,at,norm)) {
// Calculate the hit point
pt = ray.p + ray.dir * at;
// Get the mod context tm
Matrix3 tm(1);
if (mcList[0]->tm) tm = tm * *mcList[0]->tm;
// Transform the point and ray into mod context space
pt = pt * tm;
norm = Normalize(VectorTransform(tm,norm));
// Construct the target transformation in mod context space
Matrix3 destTM;
MatrixFromNormal(norm,destTM);
destTM.SetTrans(pt);
destTM.PreRotateZ(PI);
switch (mod->GetAxis()) {
case 0:
destTM.PreRotateY(-HALFPI);
break;
case 1:
destTM.PreRotateX(HALFPI);
break;
}
// Our current transformation... gives relative TM
Matrix3 curTM(1), relTM, id(1);
mod->tmControl->GetValue(t,&curTM,valid,CTRL_RELATIVE);
relTM = Inverse(curTM) * destTM;
// Here's the modifications we need to make to get there
tm.IdentityMatrix();
tm.SetTrans(curTM.GetTrans());
AffineParts parts;
decomp_affine(relTM,&parts);
Point3 delta = destTM.GetTrans()-curTM.GetTrans();
mod->Rotate(t,id,tm,parts.q);
mod->Move(t,id,id,delta);
break;
}
}
nodeList.DisposeTemporary();
ip->ReleaseViewport(vpt);
}
int FaceAlignMouseProc::proc(
HWND hWnd, int msg, int point, int flags, IPoint2 m)
{
switch (msg) {
case MOUSE_POINT:
if (point==0) {
theHold.Begin();
ip->RedrawViews(ip->GetTime(),REDRAW_BEGIN);
} else {
theHold.Accept(0);
ip->RedrawViews(ip->GetTime(),REDRAW_END);
}
break;
case MOUSE_MOVE: {
theHold.Restore();
FaceAlignMap(hWnd,m);
ip->RedrawViews(ip->GetTime(),REDRAW_INTERACTIVE);
break;
}
case MOUSE_ABORT:
theHold.Cancel();
ip->RedrawViews(ip->GetTime(),REDRAW_END);
break;
case MOUSE_FREEMOVE:
SetCursor(ip->GetSysCursor(SYSCUR_SELECT));
break;
}
return TRUE;
}
void FaceAlignMode::EnterMode()
{
mod->EnterNormalAlign();
}
void FaceAlignMode::ExitMode()
{
mod->ExitNormalAlign();
}
void RegionFitMouseProc::RegionFitMap(HWND hWnd,IPoint2 m)
{
ViewExp *vpt = ip->GetViewport(hWnd);
if (!vpt) return;
// Get mod contexts and nodes for this modifier
ModContextList mcList;
INodeTab nodeList;
ip->GetModContexts(mcList,nodeList);
// Viewport tm
Matrix3 vtm;
vpt->GetAffineTM(vtm);
vtm = Inverse(vtm);
// Node tm
Matrix3 ntm = nodeList[0]->GetObjectTM(ip->GetTime());
// MC tm
Matrix3 mctm(1);
if (mcList[0]->tm) mctm = *mcList[0]->tm;
// Current val of tmCont.. remove any scale
Matrix3 ctm(1);
mod->tmControl->GetValue(ip->GetTime(),&ctm,FOREVER,CTRL_RELATIVE);
AffineParts parts;
decomp_affine(ctm, &parts);
parts.q.MakeMatrix(ctm);
ctm.Translate(parts.t);
// Compute the inverse world space tm for the gizmo
Matrix3 iwtm = Inverse(ctm * Inverse(mctm) * ntm);
// Calculate a ray from the two mouse points
Ray mray, omray;
float at;
Point3 p1, p2;
vpt->MapScreenToWorldRay(float(m.x), float(m.y),mray);
vpt->MapScreenToWorldRay(float(om.x), float(om.y),omray);
// Back transform the rays into gizmo space
mray.p = iwtm * mray.p;
mray.dir = VectorTransform(iwtm, mray.dir);
omray.p = iwtm * omray.p;
omray.dir = VectorTransform(iwtm, omray.dir);
float dir, pnt, odir, opnt;
switch (mod->GetAxis()) {
case 0:
dir = mray.dir.x; odir = omray.dir.x;
pnt = mray.p.x; opnt = omray.p.x;
break;
case 1:
dir = mray.dir.y; odir = omray.dir.y;
pnt = mray.p.y; opnt = omray.p.y;
break;
case 2:
dir = mray.dir.z; odir = omray.dir.z;
pnt = mray.p.z; opnt = omray.p.z;
break;
}
#define EPSILON 0.001
// Make sure we're going to hit
if (fabs(dir)>EPSILON && fabs(odir)>EPSILON) {
// Compute the point of intersection
at = -pnt/dir;
p1 = mray.p + at*mray.dir;
at = -opnt/odir;
p2 = omray.p + at*omray.dir;
// Center the map in the region
ctm.PreTranslate((p1+p2)/2.0f);
// Compute scale factors and scale
float sx;
float sy;
switch (mod->GetAxis()) {
case 0:
sx = (float)fabs(p1.z-p2.z);
sy = (float)fabs(p1.y-p2.y);
break;
case 1:
sx = (float)fabs(p1.x-p2.x);
sy = (float)fabs(p1.z-p2.z);
break;
case 2:
sx = (float)fabs(p1.x-p2.x);
sy = (float)fabs(p1.y-p2.y);
break;
}
// Scale params instead of the matrix
TimeValue t = ip->GetTime();
mod->SetWidth(t,sx);
mod->SetLength(t,sy);
/*
if (sx>0.0f && sy>0.0f) {
ctm.PreScale(Point3(sx,sy,1.0f));
}
*/
// Plug-in the new value
SetXFormPacket pckt(ctm);
mod->tmControl->SetValue(ip->GetTime(), &pckt);
}
nodeList.DisposeTemporary();
ip->ReleaseViewport(vpt);
ip->RedrawViews(ip->GetTime());
}
int RegionFitMouseProc::proc(
HWND hWnd, int msg, int point, int flags, IPoint2 m)
{
switch (msg) {
case MOUSE_PROPCLICK:
ip->SetStdCommandMode(CID_OBJMOVE);
break;
case MOUSE_POINT:
if (point==0) {
om = m;
theHold.Begin();
ip->RedrawViews(ip->GetTime(),REDRAW_BEGIN);
} else {
theHold.Accept(0);
ip->RedrawViews(ip->GetTime(),REDRAW_END);
}
break;
case MOUSE_MOVE: {
theHold.Restore();
RegionFitMap(hWnd,m);
ip->RedrawViews(ip->GetTime(),REDRAW_INTERACTIVE);
break;
}
case MOUSE_ABORT:
theHold.Cancel();
ip->RedrawViews(ip->GetTime(),REDRAW_END);
break;
case MOUSE_FREEMOVE:
SetCursor(ip->GetSysCursor(SYSCUR_SELECT));
break;
}
return TRUE;
}
void RegionFitMode::EnterMode()
{
mod->EnterRegionFit();
}
void RegionFitMode::ExitMode()
{
mod->ExitRegionFit();
}
//--- PickAcquire -------------------------------------------------------
static BOOL CALLBACK AcquireTypeDlgProc(
HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static int type = IDC_ACQUIRE_REL;
switch (msg) {
case WM_INITDIALOG:
CheckRadioButton(hWnd,IDC_ACQUIRE_REL,IDC_ACQUIRE_ABS,type);
CenterWindow(hWnd,GetParent(hWnd));
break;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
if (IsDlgButtonChecked(hWnd,IDC_ACQUIRE_REL))
type = IDC_ACQUIRE_REL;
else type = IDC_ACQUIRE_ABS;
EndDialog(hWnd,type);
break;
case IDCANCEL:
EndDialog(hWnd,-1);
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
static BOOL GetAcquireType(HWND hWnd,int &type)
{
type = DialogBox(
hInstance,
MAKEINTRESOURCE(IDD_MAP_ACQUIRE),
hWnd,
AcquireTypeDlgProc);
if (type<0) return FALSE;
else return TRUE;
}
MappingMod *PickAcquire::FindFirstMap(ReferenceTarget *ref)
{
MappingMod *mod;
if (mod = GetMappingInterface(ref)) {
if (!mod->TestAFlag(A_MOD_DISABLED)) return mod;
}
for (int i=ref->NumRefs()-1; i>=0; i--) {
ReferenceTarget *cref = ref->GetReference(i);
if (cref) {
if (mod = FindFirstMap(cref)) return mod;
}
}
return NULL;
}
BOOL PickAcquire::Filter(INode *node)
{
MappingMod *amod = FindFirstMap(node->GetObjectRef());
if (amod!=mod && amod) return TRUE;
else return FALSE;
}
BOOL PickAcquire::HitTest(
IObjParam *ip,HWND hWnd,ViewExp *vpt,IPoint2 m,int flags)
{
INode *node =
ip->PickNode(hWnd,m,this);
return node ? TRUE : FALSE;
}
class PickAcquireSourceMC : public ModContextEnumProc {
public:
ModContext *mc;
PickAcquireSourceMC() {mc = NULL;}
BOOL proc(ModContext *mc) {
this->mc = mc;
return FALSE;
}
};
BOOL PickAcquire::Pick(IObjParam *ip,ViewExp *vpt)
{
INode *node = vpt->GetClosestHit();
assert(node);
MappingMod *amod = FindFirstMap(node->GetObjectRef());
if (amod) {
int type;
if (!GetAcquireType(ip->GetMAXHWnd(),type)) return TRUE;
// Get our node and mod context
ModContextList mcList;
INodeTab nodes;
ip->GetModContexts(mcList,nodes);
assert(nodes.Count());
// Get the source mod's mod context
PickAcquireSourceMC pasmc;
amod->EnumModContexts(&pasmc);
assert(pasmc.mc);
// Do it!
theHold.Begin();
AcquireMapping(mod,mcList[0],nodes[0],amod,pasmc.mc,node,type);
theHold.Accept(_T("Acquire Mapping"));
nodes.DisposeTemporary();
}
return TRUE;
}
void PickAcquire::EnterMode(IObjParam *ip)
{
mod->EnterAcquire();
}
void PickAcquire::ExitMode(IObjParam *ip)
{
mod->ExitAcquire();
}
void PickAcquire::AcquireMapping(
MappingMod *toMod, ModContext *toMC, INode *toNode,
MappingMod *fromMod, ModContext *fromMC, INode *fromNode,
int type)
{
// Build the mats
Matrix3 fromNTM(1);
Matrix3 toNTM(1);
if (type==IDC_ACQUIRE_ABS) {
fromNTM = fromNode->GetObjectTM(ip->GetTime());
toNTM = toNode->GetObjectTM(ip->GetTime());
}
Matrix3 fromTM = fromMod->CompMatrix(ip->GetTime(),fromMC,&fromNTM,FALSE,type==IDC_ACQUIRE_ABS);
Matrix3 destTM = fromTM * Inverse(toNTM);
if (toMC->tm) destTM = destTM * (*toMC->tm);
if (type==IDC_ACQUIRE_ABS && toMod->TestAFlag(A_PLUGIN1)) {
switch (toMod->GetMapType()) {
case MAP_BOX:
case MAP_PLANAR:
destTM.PreRotateZ(-PI);
break;
case MAP_BALL:
case MAP_SPHERICAL:
case MAP_CYLINDRICAL:
destTM.PreRotateZ(-HALFPI);
break;
}
}
// Set the TM
SetXFormPacket pckt(destTM);
toMod->tmControl->SetValue(ip->GetTime(),&pckt);
toMod->SetMapType(fromMod->GetMapType());
TimeValue t = ip->GetTime();
for (int i=0; i<3; i++) {
toMod->SetTile(t, i, fromMod->GetTile(t,i));
toMod->SetFlip(i, fromMod->GetFlip(i));
}
// Copy length/width/height
toMod->SetLength(t,fromMod->GetLength(t));
toMod->SetWidth(t,fromMod->GetWidth(t));
toMod->SetHeight(t,fromMod->GetHeight(t));
if (type!=IDC_ACQUIRE_ABS) {
toMod->SetAxis(fromMod->GetAxis());
} else {
toMod->SetAxis(2);
}
ip->RedrawViews(ip->GetTime());
}
//--- MapDlgProc -----------------------------------------------------
class MapDlgProc : public ParamMapUserDlgProc {
public:
MapMod *mod;
MapDlgProc(MapMod *m) {mod = m;}
BOOL DlgProc(TimeValue t,IParamMap *map,HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam);
void DeleteThis() {delete this;}
void DoBitmapFit(HWND hWnd);
};
void MapDlgProc::DoBitmapFit(HWND hWnd)
{
BitmapInfo bi;
TheManager->SelectFileInputEx(
&bi, hWnd, GetString(IDS_RB_SELECTIMAGE));
if (bi.Name()[0]) {
TheManager->GetImageInfo(&bi);
mod->aspect = bi.Aspect() * float(bi.Width())/float(bi.Height());
mod->flags |= CONTROL_ASPECT|CONTROL_HOLD;
mod->NotifyDependents(FOREVER,PART_TEXMAP,REFMSG_CHANGE);
}
}
BOOL MapDlgProc::DlgProc(
TimeValue t,IParamMap *map,HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
switch (msg) {
case WM_INITDIALOG:
SendMessage(GetDlgItem(hWnd,IDC_MAP_FITREGION),CC_COMMAND,CC_CMD_SET_TYPE,CBT_CHECK);
SendMessage(GetDlgItem(hWnd,IDC_MAP_FITREGION),CC_COMMAND,CC_CMD_HILITE_COLOR,GREEN_WASH);
SendMessage(GetDlgItem(hWnd,IDC_MAP_NORMALALIGN),CC_COMMAND,CC_CMD_SET_TYPE,CBT_CHECK);
SendMessage(GetDlgItem(hWnd,IDC_MAP_NORMALALIGN),CC_COMMAND,CC_CMD_HILITE_COLOR,GREEN_WASH);
SendMessage(GetDlgItem(hWnd,IDC_MAP_ACQUIRE),CC_COMMAND,CC_CMD_SET_TYPE,CBT_CHECK);
SendMessage(GetDlgItem(hWnd,IDC_MAP_ACQUIRE),CC_COMMAND,CC_CMD_HILITE_COLOR,GREEN_WASH);
break;
case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDC_MAP_SPHERE:
case IDC_MAP_BALL:
mod->flags |= CONTROL_UNIFORM|CONTROL_HOLD;
mod->NotifyDependents(FOREVER,PART_TEXMAP,REFMSG_CHANGE);
break;
case IDC_MAP_FIT:
mod->flags |= CONTROL_FIT|CONTROL_HOLD;
mod->NotifyDependents(FOREVER,PART_TEXMAP,REFMSG_CHANGE);
break;
case IDC_MAP_CENTER:
mod->flags |= CONTROL_CENTER|CONTROL_HOLD;
mod->NotifyDependents(FOREVER,PART_TEXMAP,REFMSG_CHANGE);
break;
case IDC_MAP_BITMAPFIT:
DoBitmapFit(hWnd);
break;
case IDC_MAP_ACQUIRE:
mod->ip->SetPickMode(&mod->pickAcquire);
break;
case IDC_MAP_NORMALALIGN:
if (mod->ip->GetCommandMode()->ID()==CID_FACEALIGNMAP) {
mod->ip->SetStdCommandMode(CID_OBJMOVE);
} else {
mod->ip->SetCommandMode(mod->faceAlignMode);
}
break;
case IDC_MAP_RESET:
theHold.Begin();
mod->ReplaceReference(TM_REF,NULL);
mod->flags |= CONTROL_FIT|CONTROL_CENTER|CONTROL_INIT;
theHold.Accept(0);
mod->NotifyDependents(FOREVER,PART_TEXMAP,REFMSG_CHANGE);
break;
case IDC_MAP_VIEWALIGN:
theHold.Begin();
mod->ViewportAlign();
theHold.Accept(0);
break;
case IDC_MAP_FITREGION:
if (mod->ip->GetCommandMode()->ID()==CID_REGIONFIT) {
mod->ip->SetStdCommandMode(CID_OBJMOVE);
} else {
mod->ip->SetCommandMode(mod->regionFitMode);
}
break;
}
break;
}
return FALSE;
}
//--- MapMod methods ---------------------------------------------------
MapMod::MapMod(BOOL create)
{
SetAFlag(A_PLUGIN1);
if (create) flags = CONTROL_CENTER|CONTROL_FIT|CONTROL_INIT;
else flags = 0;
MakeRefByID(FOREVER, PBLOCK_REF,
CreateParameterBlock(descVer3, PBLOCK_LENGTH, CURRENT_VERSION));
tmControl = NULL;
pblock->SetValue(PB_UTILE,0,1.0f);
pblock->SetValue(PB_VTILE,0,1.0f);
pblock->SetValue(PB_WTILE,0,1.0f);
pblock->SetValue(PB_WIDTH,0,1.0f);
pblock->SetValue(PB_LENGTH,0,1.0f);
pblock->SetValue(PB_HEIGHT,0,1.0f);
pblock->SetValue(PB_AXIS,0,2);
}
#define NEWMAP_CHUNKID 0x0100
IOResult MapMod::Load(ILoad *iload)
{
Modifier::Load(iload);
ClearAFlag(A_PLUGIN1);
IOResult res;
while (IO_OK==(res=iload->OpenChunk())) {
switch (iload->CurChunkID()) {
case NEWMAP_CHUNKID:
SetAFlag(A_PLUGIN1);
break;
}
iload->CloseChunk();
if (res!=IO_OK) return res;
}
iload->RegisterPostLoadCallback(
new FixDimsPLCB(this));
iload->RegisterPostLoadCallback(
new ParamBlockPLCB(versions,NUM_OLDVERSIONS,&curVersion,this,PBLOCK_REF));
return IO_OK;
}
IOResult MapMod::Save(ISave *isave)
{
Modifier::Save(isave);
if (TestAFlag(A_PLUGIN1)) {
isave->BeginChunk(NEWMAP_CHUNKID);
isave->EndChunk();
}
return IO_OK;
}
void MapMod::BeginEditParams(IObjParam *ip, ULONG flags,Animatable *prev)
{
this->ip = ip;
editMod = this;
// Add our sub object type
TSTR type1( GetString(IDS_RB_APPARATUS));
const TCHAR *ptype[] = {type1};
ip->RegisterSubObjectTypes(ptype, 1);
// Create sub object editing modes.
moveMode = new MoveModBoxCMode(this,ip);
rotMode = new RotateModBoxCMode(this,ip);
uscaleMode = new UScaleModBoxCMode(this,ip);
nuscaleMode = new NUScaleModBoxCMode(this,ip);
squashMode = new SquashModBoxCMode(this,ip);
faceAlignMode = new FaceAlignMode(this,ip);
regionFitMode = new RegionFitMode(this,ip);
pickAcquire.mod = this;
pickAcquire.ip = ip;
pmapParam = CreateCPParamMap(
descParam,PARAMDESC_LENGH,
pblock,
ip,
hInstance,
MAKEINTRESOURCE(IDD_UVWMAPPARAM),
GetString(IDS_RB_PARAMETERS),
0);
pmapParam->SetUserDlgProc(new MapDlgProc(this));
TimeValue t = ip->GetTime();
NotifyDependents(Interval(t,t), PART_ALL, REFMSG_BEGIN_EDIT);
NotifyDependents(Interval(t,t), PART_ALL, REFMSG_MOD_DISPLAY_ON);
SetAFlag(A_MOD_BEING_EDITED);
}
void MapMod::EndEditParams(IObjParam *ip, ULONG flags,Animatable *next)
{
this->ip = NULL;
editMod = NULL;
TimeValue t = ip->GetTime();
ClearAFlag(A_MOD_BEING_EDITED);
NotifyDependents(Interval(t,t), PART_ALL, REFMSG_END_EDIT);
NotifyDependents(Interval(t,t), PART_ALL, REFMSG_MOD_DISPLAY_OFF);
ip->ClearPickMode();
pickAcquire.mod = NULL;
pickAcquire.ip = NULL;
ip->DeleteMode(moveMode);
ip->DeleteMode(rotMode);
ip->DeleteMode(uscaleMode);
ip->DeleteMode(nuscaleMode);
ip->DeleteMode(squashMode);
ip->DeleteMode(faceAlignMode);
ip->DeleteMode(regionFitMode);
delete moveMode; moveMode = NULL;
delete rotMode; rotMode = NULL;
delete uscaleMode; uscaleMode = NULL;
delete nuscaleMode; nuscaleMode = NULL;
delete squashMode; squashMode = NULL;
delete faceAlignMode; faceAlignMode = NULL;
delete regionFitMode; regionFitMode = NULL;
DestroyCPParamMap(pmapParam);
}
void MapMod::EnterNormalAlign()
{
SendMessage(GetDlgItem(pmapParam->GetHWnd(),IDC_MAP_NORMALALIGN),CC_COMMAND,CC_CMD_SET_STATE,1);
}
void MapMod::ExitNormalAlign()
{
SendMessage(GetDlgItem(pmapParam->GetHWnd(),IDC_MAP_NORMALALIGN),CC_COMMAND,CC_CMD_SET_STATE,0);
}
void MapMod::EnterRegionFit()
{
SendMessage(GetDlgItem(pmapParam->GetHWnd(),IDC_MAP_FITREGION),CC_COMMAND,CC_CMD_SET_STATE,1);
}
void MapMod::ExitRegionFit()
{
SendMessage(GetDlgItem(pmapParam->GetHWnd(),IDC_MAP_FITREGION),CC_COMMAND,CC_CMD_SET_STATE,0);
}
void MapMod::EnterAcquire()
{
SendMessage(GetDlgItem(pmapParam->GetHWnd(),IDC_MAP_ACQUIRE),CC_COMMAND,CC_CMD_SET_STATE,1);
}
void MapMod::ExitAcquire()
{
SendMessage(GetDlgItem(pmapParam->GetHWnd(),IDC_MAP_ACQUIRE),CC_COMMAND,CC_CMD_SET_STATE,0);
}
float MapMod::GetLength(TimeValue t)
{
float f;
pblock->GetValue(PB_LENGTH,t,f,FOREVER);
return f;
}
float MapMod::GetWidth(TimeValue t)
{
float f;
pblock->GetValue(PB_WIDTH,t,f,FOREVER);
return f;
}
float MapMod::GetHeight(TimeValue t)
{
float f;
pblock->GetValue(PB_HEIGHT,t,f,FOREVER);
return f;
}
int MapMod::GetAxis()
{
int a;
pblock->GetValue(PB_AXIS,0,a,FOREVER);
return a;
}
void MapMod::SetLength(TimeValue t,float v)
{
pblock->SetValue(PB_LENGTH,t,v);
}
void MapMod::SetWidth(TimeValue t,float v)
{
pblock->SetValue(PB_WIDTH,t,v);
}
void MapMod::SetHeight(TimeValue t,float v)
{
pblock->SetValue(PB_HEIGHT,t,v);
}
void MapMod::SetAxis(int v)
{
pblock->SetValue(PB_AXIS,0,v);
}
int MapMod::GetMapType()
{
int type;
pblock->GetValue(PB_MAPTYPE,0,type,FOREVER);
return type;
}
void MapMod::SetMapType(int type)
{
pblock->SetValue(PB_MAPTYPE,0,type);
if (pmapParam) pmapParam->Invalidate();
}
float MapMod::GetTile(TimeValue t,int which)
{
float tile;
pblock->GetValue(PB_UTILE+which,t,tile,FOREVER);
return tile;
}
void MapMod::SetTile(TimeValue t,int which, float tile)
{
pblock->SetValue(PB_UTILE+which,t,tile);
if (pmapParam) pmapParam->Invalidate();
}
BOOL MapMod::GetFlip(int which)
{
int flip;
pblock->GetValue(PB_UFLIP+which,0,flip,FOREVER);
return flip;
}
void MapMod::SetFlip(int which,BOOL flip)
{
pblock->SetValue(PB_UFLIP+which,0,flip);
if (pmapParam) pmapParam->Invalidate();
}
Interval MapMod::LocalValidity(TimeValue t)
{
int i;
float f;
Interval valid = FOREVER;
pblock->GetValue(PB_MAPTYPE,t,i,valid);
pblock->GetValue(PB_UTILE,t,f,valid);
pblock->GetValue(PB_VTILE,t,f,valid);
pblock->GetValue(PB_WTILE,t,f,valid);
pblock->GetValue(PB_UFLIP,t,i,valid);
pblock->GetValue(PB_VFLIP,t,i,valid);
pblock->GetValue(PB_WFLIP,t,i,valid);
pblock->GetValue(PB_LENGTH,t,f,valid);
pblock->GetValue(PB_WIDTH,t,f,valid);
pblock->GetValue(PB_HEIGHT,t,f,valid);
pblock->GetValue(PB_AXIS,t,i,valid);
if (tmControl) {
Matrix3 tm(1);
tmControl->GetValue(t,&tm,valid,CTRL_RELATIVE);
}
return valid;
}
RefTargetHandle MapMod::Clone(RemapDir& remap)
{
MapMod* newmod = new MapMod(FALSE);
if (TestAFlag(A_PLUGIN1))
newmod->SetAFlag(A_PLUGIN1);
else newmod->ClearAFlag(A_PLUGIN1);
newmod->ReplaceReference(PBLOCK_REF,pblock->Clone(remap));
if (tmControl) {
newmod->ReplaceReference(TM_REF,tmControl->Clone(remap));
}
return newmod;
}
BOOL MapMod::AssignController(Animatable *control,int subAnim)
{
if (subAnim==TM_REF) {
ReplaceReference(TM_REF,(ReferenceTarget*)control);
NotifyDependents(FOREVER,0,REFMSG_CONTROLREF_CHANGE);
NotifyDependents(FOREVER,0,REFMSG_CHANGE);
return TRUE;
} else {
return FALSE;
}
}
int MapMod::SubNumToRefNum(int subNum)
{
if (subNum==TM_REF)
return TM_REF;
else return -1;
}
RefTargetHandle MapMod::GetReference(int i)
{
switch (i) {
case TM_REF: return tmControl;
case PBLOCK_REF: return pblock;
default: return NULL;
}
}
void MapMod::SetReference(int i, RefTargetHandle rtarg)
{
switch (i) {
case TM_REF: tmControl = (Control*)rtarg; break;
case PBLOCK_REF: pblock = (IParamBlock*)rtarg; break;
}
}
Animatable* MapMod::SubAnim(int i)
{
switch (i) {
case TM_REF: return tmControl;
case PBLOCK_REF: return pblock;
default: return NULL;
}
}
TSTR MapMod::SubAnimName(int i)
{
switch (i) {
case TM_REF: return GetString(IDS_RB_GIZMO);
case PBLOCK_REF: return GetString(IDS_RB_PARAMETERS);
default: return TSTR(_T(""));
}
}
RefResult MapMod::NotifyRefChanged(
Interval changeInt,
RefTargetHandle hTarget,
PartID& partID,
RefMessage message)
{
switch (message) {
case REFMSG_CHANGE:
if (editMod==this && pmapParam) pmapParam->Invalidate();
break;
case REFMSG_GET_PARAM_DIM: {
GetParamDim *gpd = (GetParamDim*)partID;
switch (gpd->index) {
case PB_LENGTH:
case PB_WIDTH:
case PB_HEIGHT: gpd->dim = stdWorldDim; break;
default: gpd->dim = defaultDim; break;
}
return REF_STOP;
}
case REFMSG_GET_PARAM_NAME: {
GetParamName *gpn = (GetParamName*)partID;
switch (gpn->index) {
case PB_UTILE: gpn->name = GetString(IDS_RB_UTILE); break;
case PB_VTILE: gpn->name = GetString(IDS_RB_VTILE); break;
case PB_WTILE: gpn->name = GetString(IDS_RB_WTILE); break;
case PB_LENGTH: gpn->name = GetString(IDS_RB_LENGTH); break;
case PB_WIDTH: gpn->name = GetString(IDS_RB_WIDTH); break;
case PB_HEIGHT: gpn->name = GetString(IDS_RB_HEIGHT); break;
default: gpn->name = TSTR(_T("")); break;
}
return REF_STOP;
}
}
return REF_SUCCEED;
}
void MapMod::ActivateSubobjSel(int level, XFormModes& modes )
{
switch (level) {
case 1: // Modifier box
modes = XFormModes(moveMode,rotMode,nuscaleMode,uscaleMode,squashMode,NULL);
break;
}
NotifyDependents(FOREVER,PART_DISPLAY,REFMSG_CHANGE);
}
// --- Modify Object ---------------------------------------------------
void MapMod::ModifyObject(TimeValue t, ModContext &mc, ObjectState *os, INode *node)
{
// If it's not a mappable object then we can't help
Object *obj = os->obj;
if (!obj->IsMappable()) return;
// Get pblock values
int type, uflip, vflip, wflip, cap, channel;
float utile, vtile, wtile;
pblock->GetValue(PB_MAPTYPE,t,type,FOREVER);
pblock->GetValue(PB_UTILE,t,utile,FOREVER);
pblock->GetValue(PB_VTILE,t,vtile,FOREVER);
pblock->GetValue(PB_WTILE,t,wtile,FOREVER);
pblock->GetValue(PB_UFLIP,t,uflip,FOREVER);
pblock->GetValue(PB_VFLIP,t,vflip,FOREVER);
pblock->GetValue(PB_WFLIP,t,wflip,FOREVER);
pblock->GetValue(PB_CAP,t,cap,FOREVER);
pblock->GetValue(PB_CHANNEL,t,channel,FOREVER);
// Prepare the controller and set up mats
if (!tmControl || (flags&CONTROL_OP) || (flags&CONTROL_INITPARAMS))
InitControl(mc,obj,type,t);
Matrix3 tm;
tm = Inverse(CompMatrix(t,&mc,NULL));
obj->ApplyUVWMap(type,utile,vtile,wtile,uflip,vflip,wflip,cap,tm,channel);
// The tex mapping depends on the geom and topo so make sure the validity interval reflects this.
Interval iv = LocalValidity(t);
iv = iv & os->obj->ChannelValidity(t,GEOM_CHAN_NUM);
iv = iv & os->obj->ChannelValidity(t,TOPO_CHAN_NUM);
os->obj->UpdateValidity(TEXMAP_CHAN_NUM,iv);
}
static int lStart[12] = {0,1,3,2,4,5,7,6,0,1,2,3};
static int lEnd[12] = {1,3,2,0,5,7,6,4,4,5,6,7};
static void DoBoxIcon(BOOL sel,float length, PolyLineProc& lp)
{
Point3 pt[3];
length *= 0.5f;
Box3 box;
box.pmin = Point3(-length,-length,-length);
box.pmax = Point3( length, length, length);
if (sel) //lp.SetLineColor(1.0f,1.0f,0.0f);
lp.SetLineColor(GetUIColor(COLOR_SEL_GIZMOS));
else //lp.SetLineColor(0.85f,0.5f,0.0f);
lp.SetLineColor(GetUIColor(COLOR_GIZMOS));
for (int i=0; i<12; i++) {
pt[0] = box[lStart[i]];
pt[1] = box[lEnd[i]];
lp.proc(pt,2);
}
}
//--- MappingMod methods -----------------------------------------------
void* MappingMod::GetInterface(ULONG id)
{
if (id==I_MAPPINGINTERFACE) return this;
else return Modifier::GetInterface(id);
}
void MappingMod::InitControl(
ModContext &mc,Object *obj,int type,TimeValue t)
{
Box3 box;
Matrix3 tm;
if (tmControl==NULL) {
MakeRefByID(FOREVER,0,NewDefaultMatrix3Controller());
NotifyDependents(FOREVER,0,REFMSG_CONTROLREF_CHANGE);
}
if (flags&CONTROL_INIT) {
SuspendAnimate();
AnimateOff();
// Rotate the seem to the back
SetXFormPacket pckt(Quat(RotateZMatrix(PI)),TRUE);
tmControl->SetValue(t,&pckt,TRUE,CTRL_RELATIVE);
ResumeAnimate();
}
if (flags&CONTROL_INITPARAMS) {
SetLength(0,2.0f);
SetWidth(0,2.0f);
if (type==MAP_BALL ||
type==MAP_SPHERICAL ||
type==MAP_BOX) {
SetHeight(0,2.0f);
} else {
SetHeight(0,1.0f);
}
SetAxis(2);
}
if (!(flags&CONTROL_OP)) {
flags = 0;
return;
}
if (flags&CONTROL_HOLD) theHold.Begin();
Matrix3 oldtm = tm = Inverse(CompMatrix(t,&mc,NULL,FALSE));
AffineParts parts;
decomp_affine(tm, &parts);
parts.q.MakeMatrix(tm);
tm.Translate(parts.t);
Matrix3 mctm(1);
if (mc.tm) mctm = *mc.tm;
tm.Scale(Point3(
Length(mctm.GetRow(0)),
Length(mctm.GetRow(1)),
Length(mctm.GetRow(2))
));
Point3 s;
s.x = GetWidth(t);
s.y = GetLength(t);
s.z = GetHeight(t);
obj->GetDeformBBox(t,box,&tm,TRUE);
box.Scale(1.001f); // prevent wrap-around on sides of boxes
if (flags&CONTROL_ASPECT &&
(type==MAP_PLANAR ||
type==MAP_BOX ||
type==MAP_CYLINDRICAL)) {
if (type==MAP_PLANAR || type==MAP_BOX) {
float w = aspect*s.y;
s.x *= w / s.x;
s.z *= s.y / s.z;
} else
if (type==MAP_CYLINDRICAL) {
float w = (s.x+s.y)*PI;
s.z *= w/(aspect*s.z);
}
}
if (flags&CONTROL_UNIFORM) {
float av = (s.x + s.y + s.z)/3.0f;
s.x = s.y = s.z = av;
}
if (flags&CONTROL_FIT) {
Point3 w = box.Width();
if (box.IsEmpty()) w = Point3(10.0f,10.0f,10.0f);
if (type==MAP_PLANAR) {
s.x = w.x==0.0f ? 1.0f : w.x;
s.y = w.y==0.0f ? 1.0f : w.y;
s.z = w.z==0.0f ? 1.0f : w.z;
} else
if (type==MAP_BOX) {
s.x = w.x==0.0f ? 1.0f : w.x;
s.y = w.y==0.0f ? 1.0f : w.y;
s.z = w.z==0.0f ? 1.0f : w.z;
} else
if (type==MAP_SPHERICAL || type==MAP_BALL) {
float max = w.x;
if (w.y>max) max = w.y;
if (w.z>max) max = w.z;
if (max==0.0f) max = 1.0f;
s.x = s.y = s.z = max;
} else {
if (w.x>w.y) s.x = s.y = w.x;
else s.x = s.y = w.y;
s.z = w.z;
if (s.x==0.0f) s.x = 1.0f;
if (s.y==0.0f) s.y = 1.0f;
if (s.z==0.0f) s.z = 1.0f;
}
}
if (flags&(CONTROL_CENTER|CONTROL_FIT)) {
Box3 sbox;
obj->GetDeformBBox(t,sbox,&oldtm,TRUE);
Point3 cent = sbox.Center();
cent = VectorTransform(Inverse(oldtm),cent);
cent = VectorTransform(mctm,cent);
SetXFormPacket pckt(
cent, //sbox.Center(),
Matrix3(1),
Matrix3(1));
//Inverse(oldtm));
SuspendAnimate();
AnimateOff();
tmControl->SetValue(t,&pckt,TRUE,CTRL_RELATIVE);
ResumeAnimate();
}
if (flags&(CONTROL_FIT|CONTROL_ASPECT|CONTROL_INITPARAMS|CONTROL_UNIFORM)) {
SuspendAnimate();
AnimateOff();
// Clear out any scale in the transform
tm = Matrix3(1);
tmControl->GetValue(t,&tm,FOREVER,CTRL_RELATIVE);
decomp_affine(tm, &parts);
parts.q.MakeMatrix(tm);
tm.Translate(parts.t);
SetXFormPacket pckt(tm);
tmControl->SetValue(t,&pckt,TRUE,CTRL_ABSOLUTE);
// Set the new dimensions
SetLength(t,s.y);
SetWidth(t,s.x);
SetHeight(t,s.z);
ResumeAnimate();
}
if (flags&CONTROL_HOLD) theHold.Accept(0);
flags = 0;
}
#if 0
void MappingMod::InitControl(ModContext &mc,Object *obj,int type,TimeValue t)
{
Box3 box;
Matrix3 tm;
if (tmControl==NULL) {
MakeRefByID(FOREVER,0,NewDefaultMatrix3Controller());
NotifyDependents(FOREVER,0,REFMSG_CONTROLREF_CHANGE);
}
if (flags&CONTROL_HOLD) theHold.Begin();
if (flags&CONTROL_INIT) {
SuspendAnimate();
AnimateOff();
// Rotate the seem to the back
SetXFormPacket pckt(Quat(RotateZMatrix(PI)),TRUE);
tmControl->SetValue(t,&pckt,TRUE,CTRL_RELATIVE);
}
tm = Inverse(CompMatrix(t,&mc,NULL));
obj->GetDeformBBox(t,box,&tm,TRUE);
box.Scale(1.001f); // prevent wrap-around on sides of boxes
if (flags&CONTROL_ASPECT &&
(type==MAP_PLANAR ||
type==MAP_BOX ||
type==MAP_CYLINDRICAL)) {
Matrix3 tm(1), id(1);
Interval valid;
tmControl->GetValue(t,&tm,valid,CTRL_RELATIVE);
Point3 s;
if (type==MAP_PLANAR || type==MAP_BOX) {
float w = aspect*Length(tm.GetRow(1));
s.x = w / Length(tm.GetRow(0));
s.y = 1.0f;
s.z = Length(tm.GetRow(1)) / Length(tm.GetRow(2));
/*
float a = (Length(tm.GetRow(0))+Length(tm.GetRow(1))+Length(tm.GetRow(2)))/3.0f;
s.x = aspect*a / Length(tm.GetRow(0));
s.y = a / Length(tm.GetRow(1));
s.z = a / Length(tm.GetRow(2));
*/
} else
if (type==MAP_CYLINDRICAL) {
// Old way where we sized the radius
/*
float lz = Length(tm.GetRow(2));
float rad = lz*aspect/(TWOPI);
s.x = rad / Length(tm.GetRow(0));
s.y = rad / Length(tm.GetRow(1));
s.z = 1.0f;
*/
// Now we size the height
float w = (Length(tm.GetRow(0))+Length(tm.GetRow(1)))*PI;
s.x = 1.0f;
s.y = 1.0f;
s.z = w/(aspect*Length(tm.GetRow(2)));
}
SetXFormPacket pckt(s,TRUE,id,tm);
tmControl->SetValue(t,&pckt,TRUE,CTRL_RELATIVE);
}
if (flags&CONTROL_UNIFORM) {
Matrix3 tm(1), id(1);
Interval valid;
tmControl->GetValue(t,&tm,valid,CTRL_RELATIVE);
float av = 0.0f;
Point3 s;
av += Length(tm.GetRow(0));
av += Length(tm.GetRow(1));
av += Length(tm.GetRow(2));
av /= 3.0f;
s.x = av/Length(tm.GetRow(0));
s.y = av/Length(tm.GetRow(1));
s.z = av/Length(tm.GetRow(2));
SetXFormPacket pckt(s,TRUE,id,tm);
tmControl->SetValue(t,&pckt,TRUE,CTRL_RELATIVE);
}
if (flags&CONTROL_FIT) {
// Get the box of the object in mod context space but unscaled
Matrix3 mat = tm;
mat.NoScale();
obj->GetDeformBBox(t,box,&mat,TRUE);
box.Scale(1.001f); // prevent wrap-around on sides of boxes
Point3 s, w = box.Width();
if (box.IsEmpty()) w = Point3(10.0f,10.0f,10.0f);
Matrix3 tm(1), id(1);
Interval valid;
tmControl->GetValue(t,&tm,valid,CTRL_RELATIVE);
if (type==MAP_PLANAR) {
s.x = w.x==0.0f ? 1.0f : w.x/2.0f;
s.y = w.y==0.0f ? 1.0f : w.y/2.0f;
s.z = w.z==0.0f ? 1.0f : w.z;
} else
if (type==MAP_BOX) {
s.x = w.x==0.0f ? 1.0f : w.x/2.0f;
s.y = w.y==0.0f ? 1.0f : w.y/2.0f;
s.z = w.z==0.0f ? 1.0f : w.z/2.0f;
} else
if (type==MAP_SPHERICAL || type==MAP_BALL) {
float max = w.x;
if (w.y>max) max = w.y;
if (w.z>max) max = w.z;
if (max==0.0f) max = 1.0f;
s.x = s.y = s.z = max/2.0f;
} else {
if (w.x>w.y) s.x = s.y = w.x/2.0f;
else s.x = s.y = w.y/2.0f;
s.z = w.z;
if (s.x==0.0f) s.x = 1.0f;
if (s.y==0.0f) s.y = 1.0f;
if (s.z==0.0f) s.z = 1.0f;
}
s.x /= Length(tm.GetRow(0));
s.y /= Length(tm.GetRow(1));
s.z /= Length(tm.GetRow(2));
SetXFormPacket pckt(s,TRUE,id,tm);
tmControl->SetValue(t,&pckt,TRUE,CTRL_RELATIVE);
// redo the box so our center op works
tm = Inverse(CompMatrix(t,&mc,NULL));
obj->GetDeformBBox(t,box,&tm,TRUE);
box.Scale(1.001f); // prevent wrap-around on sides of boxes
}
if (flags&(CONTROL_CENTER|CONTROL_FIT)) {
Matrix3 tm(1);
Interval valid;
tmControl->GetValue(t,&tm,valid,CTRL_RELATIVE);
SetXFormPacket pckt(VectorTransform(tm,box.Center()));
tmControl->SetValue(t,&pckt,TRUE,CTRL_RELATIVE);
}
if (flags&CONTROL_HOLD) theHold.Accept(0);
if (flags&CONTROL_INIT) {
ResumeAnimate();
}
flags = 0;
}
#endif
// --- Gizmo transformations ------------------------------------------
void MappingMod::Move(
TimeValue t, Matrix3& partm, Matrix3& tmAxis,
Point3& val, BOOL localOrigin)
{
#ifdef DESIGN_VER
t=0;
#endif
assert(tmControl);
SetXFormPacket pckt(val,partm,tmAxis);
tmControl->SetValue(t,&pckt,TRUE,CTRL_RELATIVE);
}
void MappingMod::Rotate(
TimeValue t, Matrix3& partm, Matrix3& tmAxis,
Quat& val, BOOL localOrigin)
{
#ifdef DESIGN_VER
t=0;
#endif
assert(tmControl);
SetXFormPacket pckt(val,localOrigin,partm,tmAxis);
tmControl->SetValue(t,&pckt,TRUE,CTRL_RELATIVE);
}
void MappingMod::Scale(
TimeValue t, Matrix3& partm, Matrix3& tmAxis,
Point3& val, BOOL localOrigin)
{
#ifdef DESIGN_VER
t=0;
#endif
assert(tmControl);
SetXFormPacket pckt(val,localOrigin,partm,tmAxis);
tmControl->SetValue(t,&pckt,TRUE,CTRL_RELATIVE);
}
Matrix3 MappingMod::CompMatrix(
TimeValue t,ModContext *mc, Matrix3 *ntm,BOOL applySize, BOOL applyAxis)
{
Matrix3 tm(1);
Interval valid;
int type = GetMapType();
if (tmControl) {
tmControl->GetValue(t,&tm,valid,CTRL_RELATIVE);
}
// Rotate icon
if (applyAxis && TestAFlag(A_PLUGIN1)) {
switch (type) {
case MAP_BOX:
case MAP_PLANAR:
tm.PreRotateZ(PI);
break;
case MAP_BALL:
case MAP_SPHERICAL:
case MAP_CYLINDRICAL:
tm.PreRotateZ(HALFPI);
break;
}
}
if (applyAxis) {
switch (GetAxis()) {
case 0:
tm.PreRotateY(-HALFPI);
break;
case 1:
tm.PreRotateX(HALFPI);
break;
}
}
if (applySize) {
Point3 s;
s.x = GetWidth(t);
s.y = GetLength(t);
s.z = GetHeight(t);
switch (type) {
case MAP_CYLINDRICAL:
case MAP_PLANAR:
s.x *= 0.5f;
s.y *= 0.5f;
break;
case MAP_BALL:
case MAP_SPHERICAL:
case MAP_BOX:
s *= 0.5f;
break;
}
tm.PreScale(s);
}
if (mc && mc->tm) {
tm = tm * Inverse(*mc->tm);
}
if (ntm) {
tm = tm * *ntm;
}
return tm;
}
void MappingMod::DoIcon(PolyLineProc& lp,BOOL sel)
{
int type = GetMapType();
switch (type) {
case MAP_BOX: DoBoxIcon(sel,2.0f,lp); break;
case MAP_PLANAR: DoPlanarMapIcon(sel,2.0f,2.0f,lp); break;
case MAP_BALL:
case MAP_SPHERICAL: DoSphericalMapIcon(sel,1.0f,lp); break;
case MAP_CYLINDRICAL: DoCylindricalMapIcon(sel,1.0f,1.0f,lp); break;
}
}
int MappingMod::HitTest(
TimeValue t, INode* inode, int type, int crossing,
int flags, IPoint2 *p, ViewExp *vpt, ModContext* mc)
{
int savedLimits;
GraphicsWindow *gw = vpt->getGW();
HitRegion hr;
MakeHitRegion(hr,type, crossing,4,p);
gw->setHitRegion(&hr);
Matrix3 modmat, ntm = inode->GetObjectTM(t);
DrawLineProc lp(gw);
gw->setRndLimits(((savedLimits = gw->getRndLimits()) | GW_PICK) & ~GW_ILLUM);
gw->clearHitCode();
if (ip && ip->GetSubObjectLevel() == 1) {
modmat = CompMatrix(t,mc,&ntm);
gw->setTransform(modmat);
DoIcon(lp,FALSE);
}
gw->setRndLimits(savedLimits);
if (gw->checkHitCode()) {
vpt->LogHit(inode, mc, gw->getHitDistance(), 0, NULL);
return 1;
}
return 0;
}
int MappingMod::Display(
TimeValue t, INode* inode, ViewExp *vpt, int flags,
ModContext *mc)
{
GraphicsWindow *gw = vpt->getGW();
Matrix3 modmat, ntm = inode->GetObjectTM(t);
DrawLineProc lp(gw);
modmat = CompMatrix(t,mc,&ntm);
gw->setTransform(modmat);
DoIcon(lp, ip&&ip->GetSubObjectLevel()==1);
return 0;
}
void MappingMod::GetWorldBoundBox(
TimeValue t,INode* inode, ViewExp *vpt, Box3& box,
ModContext *mc)
{
Matrix3 modmat, ntm = inode->GetObjTMBeforeWSM(t);
modmat = CompMatrix(t,mc,&ntm);
BoxLineProc bproc(&modmat);
DoIcon(bproc,FALSE);
box = bproc.Box();
}
void MappingMod::GetSubObjectCenters(
SubObjAxisCallback *cb,TimeValue t,INode *node,ModContext *mc)
{
Matrix3 modmat, ntm = node->GetObjectTM(t);
modmat = CompMatrix(t,mc,&ntm);
cb->Center(modmat.GetTrans(),0);
}
void MappingMod::GetSubObjectTMs(
SubObjAxisCallback *cb,TimeValue t,INode *node,ModContext *mc)
{
Matrix3 ntm = node->GetObjectTM(t), modmat;
modmat = CompMatrix(t,mc,&ntm);
cb->TM(modmat,0);
}
void FixDimsPLCB::proc(ILoad *iload)
{
if (mod->GetPBlockVersion()<mod->GetFirstParamVer()) {
mod->flags |= CONTROL_INITPARAMS;
}
delete this;
}