mirror of
https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git
synced 2025-07-13 18:17:49 -04:00
CWE Directory Reorganization
Rearrange directory structure of CWE to be loosely equivalent to the H'uru Plasma repository. Part 1: Movement of directories and files.
This commit is contained in:
108
Sources/Tools/MaxConvert/StringTokenizer.cpp
Normal file
108
Sources/Tools/MaxConvert/StringTokenizer.cpp
Normal file
@ -0,0 +1,108 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
// StringTokenizer.cpp
|
||||
|
||||
#include "StringTokenizer.h"
|
||||
#include "string.h"
|
||||
|
||||
// String Tokenizer routines
|
||||
StringTokenizer::StringTokenizer() {
|
||||
qAsTok = true;
|
||||
inQuote = false;
|
||||
this->string = this->seps = 0;
|
||||
}
|
||||
StringTokenizer::StringTokenizer(const char *string, const char *seps) {
|
||||
qAsTok = true;
|
||||
inQuote = false;
|
||||
this->string = TRACKED_NEW char[strlen(string)+1];
|
||||
strcpy(this->string,string);
|
||||
numSeps = strlen(seps);
|
||||
this->seps = TRACKED_NEW char[numSeps+1];
|
||||
strcpy(this->seps,seps);
|
||||
this->tok = this->string;
|
||||
if (isSep(*tok)) next();
|
||||
};
|
||||
StringTokenizer::~StringTokenizer() {
|
||||
delete string;
|
||||
delete seps;
|
||||
}
|
||||
hsBool StringTokenizer::hasMoreTokens() {
|
||||
return (*tok != '\0');
|
||||
};
|
||||
char *StringTokenizer::next() {
|
||||
if (*tok == '\0') return NULL;
|
||||
char *cur = tok;
|
||||
while (*tok != '\0' && !isSep(*tok)) tok++;
|
||||
if (*tok != '\0') {
|
||||
*tok = '\0';
|
||||
tok++;
|
||||
}
|
||||
while (*tok != '\0' && isSep(*tok)) tok++;
|
||||
return cur;
|
||||
};
|
||||
hsBool StringTokenizer::isSep(char c) {
|
||||
if (!qAsTok || !inQuote) {
|
||||
for (Int32 i=0; i<numSeps; i++) {
|
||||
if (seps[i] == c) return true;
|
||||
}
|
||||
}
|
||||
if (qAsTok && c=='\"') {
|
||||
inQuote = !inQuote;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
void StringTokenizer::reset(const char *string, const char *seps) {
|
||||
if (this->string) delete this->string;
|
||||
this->string = TRACKED_NEW char[strlen(string)+1];
|
||||
strcpy(this->string,string);
|
||||
if (this->seps) delete this->seps;
|
||||
numSeps = strlen(seps);
|
||||
this->seps = TRACKED_NEW char[numSeps+1];
|
||||
strcpy(this->seps,seps);
|
||||
this->tok = this->string;
|
||||
if (isSep(*tok)) next();
|
||||
}
|
||||
|
||||
void StringTokenizer::ParseQuotes(hsBool qAsTok) {
|
||||
this->qAsTok = qAsTok;
|
||||
}
|
67
Sources/Tools/MaxConvert/StringTokenizer.h
Normal file
67
Sources/Tools/MaxConvert/StringTokenizer.h
Normal file
@ -0,0 +1,67 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
// StringTokenizer.h
|
||||
#ifndef _STRING_TOKENIZER_H_
|
||||
#define _STRING_TOKENIZER_H_
|
||||
|
||||
#include "Headspin.h"
|
||||
|
||||
class StringTokenizer {
|
||||
private:
|
||||
char *seps;
|
||||
char *tok;
|
||||
hsBool isSep(char c);
|
||||
Int32 numSeps;
|
||||
hsBool qAsTok;
|
||||
hsBool inQuote;
|
||||
public:
|
||||
StringTokenizer();
|
||||
StringTokenizer(const char *string, const char *seps);
|
||||
~StringTokenizer();
|
||||
char *next();
|
||||
hsBool hasMoreTokens();
|
||||
void reset(const char *string, const char *seps);
|
||||
void ParseQuotes(hsBool qAsTok);
|
||||
char *string;
|
||||
};
|
||||
|
||||
#endif
|
885
Sources/Tools/MaxConvert/UserPropMgr.cpp
Normal file
885
Sources/Tools/MaxConvert/UserPropMgr.cpp
Normal file
@ -0,0 +1,885 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
// UserPropMgr.cpp
|
||||
|
||||
#include "hsTypes.h"
|
||||
#include "UserPropMgr.h"
|
||||
#include "hsStringTokenizer.h"
|
||||
#include "hsUtils.h"
|
||||
#include "hsHashTable.h"
|
||||
|
||||
#define REFMSG_USERPROP (REFMSG_USER + 1)
|
||||
|
||||
const UInt32 UserPropMgr::kQuickSize = 150001;//199999;
|
||||
|
||||
UserPropMgr gUserPropMgr(GetCOREInterface());
|
||||
|
||||
UserPropMgr::UserPropMgr(Interface *ip) :
|
||||
nm(0)
|
||||
{
|
||||
this->ip = ip;
|
||||
|
||||
fQuickTable = nil;
|
||||
fQuickNode = nil;
|
||||
|
||||
vProps = false;
|
||||
}
|
||||
|
||||
UserPropMgr::~UserPropMgr()
|
||||
{
|
||||
CloseQuickTable();
|
||||
}
|
||||
|
||||
void UserPropMgr::SetUserPropFlag(INode *node, const char *name, const BOOL setFlag, const Int32 hFlag)
|
||||
{
|
||||
if (setFlag) SetUserProp(node,name,NULL,hFlag);
|
||||
else ClearUserProp(node,name,hFlag);
|
||||
}
|
||||
|
||||
void UserPropMgr::ClearUserPropALL(const char *name, const Int32 hFlag)
|
||||
{
|
||||
for (int i=0; i<GetSelNodeCount(); i++)
|
||||
{
|
||||
ClearUserProp(GetSelNode(i),name,hFlag);
|
||||
}
|
||||
}
|
||||
|
||||
void UserPropMgr::SelectUserPropFlagALL(INode *node, const char *name, const BOOL flag) {
|
||||
if (node)
|
||||
{
|
||||
if (UserPropExists(node,name) == flag) ip->SelectNode(node,false);
|
||||
} else node = ip->GetRootNode();
|
||||
|
||||
for (int i=0; i<node->NumberOfChildren(); i++) {
|
||||
SelectUserPropFlagALL(node->GetChildNode(i),name,flag);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UserPropMgr::DeSelectWithOut(const char *name, const char *value) {
|
||||
BOOL oldProps = vProps;
|
||||
vProps=false;
|
||||
TSTR val;
|
||||
INode *nodes[1];
|
||||
INodeTab nodeTab;
|
||||
for (int i=0; i<GetSelNodeCount(); i++) {
|
||||
if (value) {
|
||||
if (!(GetUserProp(GetSelNode(i),name,val) && !stricmp(val,value))) {
|
||||
nodes[0] = GetSelNode(i);
|
||||
nodeTab.Append(1,nodes);
|
||||
}
|
||||
} else if (!UserPropExists(GetSelNode(i),name)) {
|
||||
nodes[0] = GetSelNode(i);
|
||||
nodeTab.Append(1,nodes);
|
||||
}
|
||||
}
|
||||
vProps=oldProps;
|
||||
if (nodeTab.Count() > 0) ip->SelectNodeTab(nodeTab,false,false);
|
||||
|
||||
}
|
||||
|
||||
void UserPropMgr::RecursiveSelectAll(INode *node) {
|
||||
if (node) {
|
||||
if (!node->Selected()) ip->SelectNode(node,false);
|
||||
} else node = ip->GetRootNode();
|
||||
|
||||
for (int i=0; i<node->NumberOfChildren(); i++) {
|
||||
RecursiveSelectAll(node->GetChildNode(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UserPropMgr::DeSelectUnAlike(INode *node) {
|
||||
theHold.Begin();
|
||||
|
||||
ip->ThawSelection();
|
||||
|
||||
RecursiveSelectAll();
|
||||
|
||||
TSTR buf;
|
||||
GetUserPropBuffer(node,buf);
|
||||
|
||||
hsStringTokenizer toker(buf," \r\n");
|
||||
toker.ParseQuotes(TRUE);
|
||||
char *tok;
|
||||
TSTR name;
|
||||
bool isName = true;
|
||||
while (tok=toker.next()) {
|
||||
if (isName) {
|
||||
if (*tok != '=') {
|
||||
name = tok;
|
||||
tok = toker.next();
|
||||
if (tok && *tok == '=') {
|
||||
tok = toker.next();
|
||||
} else tok = NULL;
|
||||
DeSelectWithOut(name,tok);
|
||||
} else isName = false;
|
||||
} else {
|
||||
isName = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TSTR undostr; undostr.printf("Select");
|
||||
theHold.Accept(undostr);
|
||||
|
||||
ip->FreezeSelection();
|
||||
|
||||
ip->RedrawViews(ip->GetTime());
|
||||
}
|
||||
|
||||
|
||||
|
||||
int UserPropMgr::RecursiveCountAlike(INode *node, BOOL MatchAll) {
|
||||
int count=0;
|
||||
if (node) {
|
||||
if (!node->IsNodeHidden() && !node->IsFrozen() && IsAlike(node,MatchAll)) count++;
|
||||
} else node = ip->GetRootNode();
|
||||
|
||||
for (int i=0; i<node->NumberOfChildren(); i++) {
|
||||
count += RecursiveCountAlike(node->GetChildNode(i),MatchAll);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
int UserPropMgr::CountAlike(BOOL MatchAll) {
|
||||
return RecursiveCountAlike(NULL, MatchAll);
|
||||
}
|
||||
|
||||
BOOL UserPropMgr::IsMatch(const char *val1, const char *val2) {
|
||||
if (!stricmp(val1,val2)) return true;
|
||||
hsStringTokenizer toker(val1," ,@");
|
||||
char *tok;
|
||||
|
||||
while (tok=toker.next()) {
|
||||
hsStringTokenizer toker2(val2," ,@");
|
||||
BOOL found = false;
|
||||
char *tok2;
|
||||
while ((tok2=toker2.next()) && !found) {
|
||||
if (tok[0] >= '1' && tok[0] <= '0') {
|
||||
if (!stricmp(tok,tok2)) found = true;
|
||||
} else if (toker.HasMoreTokens()) {
|
||||
if (!stricmp(tok,tok2)) found = true;if (!stricmp(tok,tok2)) found = true;
|
||||
} else {
|
||||
if (!strnicmp(tok,tok2,strlen(tok))) found = true;
|
||||
}
|
||||
}
|
||||
if (!found) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
BOOL UserPropMgr::IsAlike(INode *node, BOOL MatchAll) {
|
||||
TSTR buf;
|
||||
GetUserPropBuffer(node,buf);
|
||||
|
||||
BOOL oldProps = vProps;
|
||||
vProps=false;
|
||||
|
||||
hsStringTokenizer toker(buf," \r\n");
|
||||
toker.ParseQuotes(TRUE);
|
||||
char *tok;
|
||||
TSTR name;
|
||||
TSTR value;
|
||||
TSTR tval;
|
||||
BOOL match = MatchAll;
|
||||
bool isName = true;
|
||||
tok = toker.next();
|
||||
while (tok && (match==MatchAll)) {
|
||||
if (isName) {
|
||||
if (*tok != '=') {
|
||||
name = tok;
|
||||
tok = toker.next();
|
||||
if (tok && *tok == '=') {
|
||||
tok = toker.next();
|
||||
if (tok) value = tok;
|
||||
else value = "";
|
||||
tok = toker.next();
|
||||
} else value = "";
|
||||
if (GetUserProp(node,name,tval)) match = IsMatch(value,tval);
|
||||
else match = false;
|
||||
continue;
|
||||
} else isName = false;
|
||||
} else {
|
||||
isName = true;
|
||||
}
|
||||
tok=toker.next();
|
||||
}
|
||||
|
||||
if (match==MatchAll) {
|
||||
if (!vname.isNull()) match = IsMatch(vname,node->GetName());
|
||||
}
|
||||
|
||||
vProps = oldProps;
|
||||
return match;
|
||||
}
|
||||
|
||||
int UserPropMgr::GetUserPropCount(INode *node) {
|
||||
TSTR buf;
|
||||
|
||||
GetUserPropBuffer(node,buf);
|
||||
|
||||
int numProps = 0;
|
||||
|
||||
hsStringTokenizer toker(buf," \r\n");
|
||||
toker.ParseQuotes(TRUE);
|
||||
char *tok;
|
||||
bool isName = true;
|
||||
while (tok=toker.next()) {
|
||||
if (isName) {
|
||||
if (*tok != '=') {
|
||||
numProps++;
|
||||
} else isName = false;
|
||||
} else {
|
||||
isName = true;
|
||||
}
|
||||
}
|
||||
|
||||
return numProps;
|
||||
}
|
||||
|
||||
void UserPropMgr::GetUserPropBuffer(INode *node, TSTR &buf) {
|
||||
if (vProps) buf = vbuf;
|
||||
else if (node) node->GetUserPropBuffer(buf);
|
||||
else buf = "";
|
||||
}
|
||||
|
||||
void UserPropMgr::SetUserPropBuffer(INode *node, const TSTR &buf)
|
||||
{
|
||||
// QuickTable invalidate
|
||||
if (node && node == fQuickNode)
|
||||
{
|
||||
fQuickNode = nil;
|
||||
}
|
||||
|
||||
if (vProps)
|
||||
{
|
||||
vbuf = buf;
|
||||
}
|
||||
else if (node)
|
||||
{
|
||||
node->SetUserPropBuffer(buf);
|
||||
node->NotifyDependents(FOREVER, PART_ALL, REFMSG_USERPROP);
|
||||
}
|
||||
}
|
||||
|
||||
void UserPropMgr::SetUserPropFlagALL(const char *name, const BOOL setFlag, const Int32 hFlag)
|
||||
{
|
||||
for (int i=0; i<GetSelNodeCount();i++)
|
||||
{
|
||||
SetUserPropFlag(GetSelNode(i),name,setFlag,hFlag);
|
||||
}
|
||||
}
|
||||
BOOL UserPropMgr::GetUserPropFlagALL(const char *name, BOOL &isSet, const Int32 hFlag)
|
||||
{
|
||||
isSet = UserPropMgr::UserPropExists(GetSelNode(0),name,hFlag);
|
||||
|
||||
for (int i=0; i<GetSelNodeCount(); i++) {
|
||||
if (isSet != UserPropMgr::UserPropExists(GetSelNode(i),name,hFlag)) return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
INode* UserPropMgr::GetAncestorIfNeeded(INode* node, const Int32 hFlag)
|
||||
{
|
||||
if (hFlag == kParent)
|
||||
{
|
||||
if (!(node->IsRootNode() || node->GetParentNode()->IsRootNode()))
|
||||
node = node->GetParentNode();
|
||||
}
|
||||
else
|
||||
if (hFlag == kRoot)
|
||||
{
|
||||
while (!(node->IsRootNode() || node->GetParentNode()->IsRootNode()))
|
||||
node = node->GetParentNode();
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
void UserPropMgr::ClearUserProp(INode *node, const char *name, const Int32 hFlag)
|
||||
{
|
||||
node = GetAncestorIfNeeded(node,hFlag);
|
||||
|
||||
// QuickTable invalidate
|
||||
if (node && node == fQuickNode)
|
||||
{
|
||||
fQuickNode = nil;
|
||||
}
|
||||
|
||||
TSTR buf;
|
||||
GetUserPropBuffer(node,buf);
|
||||
|
||||
hsStringTokenizer toker(buf," \r\n");
|
||||
toker.ParseQuotes(TRUE);
|
||||
char *tok;
|
||||
bool isName = true;
|
||||
while (tok=toker.next())
|
||||
{
|
||||
if (isName)
|
||||
{
|
||||
if (*tok != '=')
|
||||
{
|
||||
if (!stricmp(tok,name))
|
||||
{
|
||||
char *tok2 = toker.next();
|
||||
if (tok2)
|
||||
{
|
||||
if (*tok2 == '=')
|
||||
{
|
||||
tok2 = toker.next();
|
||||
if (tok2)
|
||||
{
|
||||
tok2 = toker.next();
|
||||
if (tok2)
|
||||
{
|
||||
buf.remove(tok-toker.fString,tok2-tok);
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.remove(tok-toker.fString);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.remove(tok-toker.fString);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.remove(tok-toker.fString,tok2-tok);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.remove(tok-toker.fString);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
isName = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
isName = true;
|
||||
}
|
||||
}
|
||||
if (vProps)
|
||||
{
|
||||
vbuf = buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
node->SetUserPropBuffer(buf);
|
||||
node->NotifyDependents(FOREVER, PART_ALL, REFMSG_USERPROP);
|
||||
}
|
||||
};
|
||||
|
||||
BOOL UserPropMgr::GetUserProp(INode *node, const char *name, TSTR &value, const Int32 hFlag)
|
||||
{
|
||||
node = GetAncestorIfNeeded(node,hFlag);
|
||||
|
||||
// QuickTable lookup
|
||||
if (node && fQuickTable)
|
||||
{
|
||||
if (node != fQuickNode)
|
||||
IBuildQuickTable(node);
|
||||
return ICheckQuickEntry(name,value);
|
||||
}
|
||||
|
||||
TSTR buf;
|
||||
GetUserPropBuffer(node,buf);
|
||||
|
||||
hsStringTokenizer toker(buf," \r\n");
|
||||
toker.ParseQuotes(TRUE);
|
||||
char *tok;
|
||||
bool isName = true;
|
||||
while (tok=toker.next())
|
||||
{
|
||||
if (isName)
|
||||
{
|
||||
if (*tok != '=')
|
||||
{
|
||||
if (!stricmp(tok,name))
|
||||
{
|
||||
tok = toker.next();
|
||||
if (tok && *tok == '=')
|
||||
{
|
||||
tok = toker.next();
|
||||
if (tok) value = tok;
|
||||
else value = "";
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = "";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
isName = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
isName = true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void UserPropMgr::SetUserProp(INode *node, const char *name, const char *value, const Int32 hFlag)
|
||||
{
|
||||
node = GetAncestorIfNeeded(node,hFlag);
|
||||
|
||||
// QuickTable invalidate
|
||||
if (node && node == fQuickNode)
|
||||
{
|
||||
fQuickNode = nil;
|
||||
}
|
||||
|
||||
TSTR buf;
|
||||
GetUserPropBuffer(node,buf);
|
||||
|
||||
hsStringTokenizer toker(buf," \r\n");
|
||||
toker.ParseQuotes(TRUE);
|
||||
char *tok;
|
||||
bool isName = true;
|
||||
while (tok=toker.next())
|
||||
{
|
||||
if (isName)
|
||||
{
|
||||
if (*tok != '=')
|
||||
{
|
||||
if (!stricmp(tok,name))
|
||||
{
|
||||
char *tok2 = toker.next();
|
||||
if (tok2)
|
||||
{
|
||||
if (*tok2 == '=')
|
||||
{
|
||||
tok2 = toker.next();
|
||||
if (tok2)
|
||||
{
|
||||
tok2 = toker.next();
|
||||
if (tok2)
|
||||
{
|
||||
buf.remove(tok-toker.fString,tok2-tok);
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.remove(tok-toker.fString);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.remove(tok-toker.fString);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.remove(tok-toker.fString,tok2-tok);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.remove(tok-toker.fString);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
isName = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
isName = true;
|
||||
}
|
||||
}
|
||||
if (buf.last('\n') < buf.length()-1)
|
||||
{
|
||||
// better start with a separator
|
||||
buf += "\r\n";
|
||||
}
|
||||
buf += name;
|
||||
if (value && *value)
|
||||
{
|
||||
buf += " = ";
|
||||
if (strchr(value,' '))
|
||||
{
|
||||
buf += "\"";
|
||||
buf += value;
|
||||
buf += "\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
buf += value;
|
||||
}
|
||||
}
|
||||
buf += "\r\n";
|
||||
if (vProps)
|
||||
{
|
||||
vbuf = buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
node->SetUserPropBuffer(buf);
|
||||
node->NotifyDependents(FOREVER, PART_ALL, REFMSG_USERPROP);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BOOL UserPropMgr::GetUserPropString(INode *node, const char *name, TSTR &value, const Int32 hFlag)
|
||||
{
|
||||
return GetUserProp(node,name,value,hFlag);
|
||||
}
|
||||
void UserPropMgr::SetUserPropString(INode *node, const char *name, const char *value, const Int32 hFlag)
|
||||
{
|
||||
SetUserProp(node,name,value,hFlag);
|
||||
}
|
||||
BOOL UserPropMgr::GetUserPropFloat(INode *node, const char *name, float &value, const Int32 hFlag)
|
||||
{
|
||||
TSTR valStr;
|
||||
if (GetUserProp(node,name,valStr,hFlag))
|
||||
{
|
||||
value = (float)atof(valStr);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
void UserPropMgr::SetUserPropFloat(INode *node, const char *name, const float value, const Int32 hFlag)
|
||||
{
|
||||
char valStr[50];
|
||||
if (sprintf(valStr,"%g",value)) SetUserProp(node,name,valStr,hFlag);
|
||||
}
|
||||
BOOL UserPropMgr::GetUserPropInt(INode *node, const char *name, int &value, const Int32 hFlag)
|
||||
{
|
||||
TSTR valStr;
|
||||
if (GetUserProp(node,name,valStr,hFlag)) {
|
||||
value = atoi(valStr);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
void UserPropMgr::SetUserPropInt(INode *node, const char *name, const int value, const Int32 hFlag)
|
||||
{
|
||||
char valStr[50];
|
||||
if (sprintf(valStr,"%d",value)) SetUserProp(node,name,valStr,hFlag);
|
||||
}
|
||||
|
||||
BOOL UserPropMgr::UserPropExists(INode *node, const char *name, const Int32 hFlag)
|
||||
{
|
||||
TSTR value;
|
||||
return GetUserProp(node,name,value,hFlag);
|
||||
}
|
||||
|
||||
BOOL UserPropMgr::GetUserPropStringList(INode *node, const char *name, int &num, TSTR list[]) {
|
||||
TSTR sdata;
|
||||
if (UserPropMgr::GetUserPropString(node,name,sdata)) {
|
||||
num=0;
|
||||
hsStringTokenizer toker(sdata,", ");
|
||||
char *tok;
|
||||
while ( tok = toker.next() ) {
|
||||
list[num] = tok;
|
||||
num++;
|
||||
}
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
BOOL UserPropMgr::GetUserPropIntList(INode *node, const char *name, int &num, int list[]) {
|
||||
TSTR sdata;
|
||||
if (UserPropMgr::GetUserPropString(node,name,sdata)) {
|
||||
num=0;
|
||||
hsStringTokenizer toker(sdata,", ");
|
||||
char *tok;
|
||||
while ( tok = toker.next() ) {
|
||||
list[num] = atoi(tok);
|
||||
num++;
|
||||
}
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
BOOL UserPropMgr::GetUserPropFloatList(INode *node, const char *name, int &num, float list[]) {
|
||||
TSTR sdata;
|
||||
if (UserPropMgr::GetUserPropString(node,name,sdata)) {
|
||||
num=0;
|
||||
hsStringTokenizer toker(sdata,", ");
|
||||
char *tok;
|
||||
while ( tok = toker.next() ) {
|
||||
list[num] = (float)atof(tok);
|
||||
num++;
|
||||
}
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
BOOL UserPropMgr::GetUserPropStringALL(const char *name, TSTR &value, const Int32 hFlag)
|
||||
{
|
||||
BOOL propSet = UserPropMgr::GetUserPropString(GetSelNode(0),name,value,hFlag);
|
||||
|
||||
TSTR tvalue;
|
||||
int i=1;
|
||||
BOOL propMixed = FALSE;
|
||||
while (i < GetSelNodeCount() && !propMixed) {
|
||||
if (propSet ^ UserPropMgr::GetUserPropString(GetSelNode(i),name,tvalue,hFlag)) propMixed = TRUE;
|
||||
propMixed = (!(value == tvalue));
|
||||
i++;
|
||||
}
|
||||
|
||||
return (!propMixed);
|
||||
}
|
||||
void UserPropMgr::SetUserPropStringALL(const char *name, const char *value, const Int32 hFlag)
|
||||
{
|
||||
for (int i=0; i<GetSelNodeCount(); i++) {
|
||||
UserPropMgr::SetUserPropString(GetSelNode(i),name,value,hFlag);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL UserPropMgr::GetUserPropStringListALL(const char *name, int &num, TSTR list[]) {
|
||||
TSTR val;
|
||||
GetUserPropStringList(GetSelNode(0),name,num,list);
|
||||
return GetUserPropStringALL(name,val);
|
||||
}
|
||||
|
||||
BOOL UserPropMgr::GetUserPropIntListALL(const char *name, int &num, int *list) {
|
||||
TSTR val;
|
||||
GetUserPropIntList(GetSelNode(0),name,num,list);
|
||||
return GetUserPropStringALL(name,val);
|
||||
}
|
||||
|
||||
BOOL UserPropMgr::GetUserPropFloatListALL(const char *name, int &num, float *list) {
|
||||
TSTR val;
|
||||
GetUserPropFloatList(GetSelNode(0),name,num,list);
|
||||
return GetUserPropStringALL(name,val);
|
||||
}
|
||||
|
||||
BOOL UserPropMgr::GetNodeNameALL(TSTR &name) {
|
||||
if (vProps) name = vname;
|
||||
else if (ip->GetSelNodeCount() == 1) name = ip->GetSelNode(0)->GetName();
|
||||
else return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void UserPropMgr::SetNodeNameALL(const char *name) {
|
||||
if (vProps) {
|
||||
vname = name;
|
||||
} else {
|
||||
if (ip->GetSelNodeCount() > 1) {
|
||||
TSTR uName;
|
||||
for (int i=0; i<ip->GetSelNodeCount(); i++) {
|
||||
uName = name;
|
||||
ip->MakeNameUnique(uName);
|
||||
ip->GetSelNode(i)->SetName(uName);
|
||||
}
|
||||
} else ip->GetSelNode(0)->SetName((char*)name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UserPropMgr::LoadVirtualProps(BOOL reset) {
|
||||
if (reset)
|
||||
{
|
||||
vbuf = "";
|
||||
vname = "";
|
||||
}
|
||||
vProps = true;
|
||||
}
|
||||
void UserPropMgr::DestroyVirtualProps() {
|
||||
vProps = false;
|
||||
}
|
||||
BOOL UserPropMgr::IsVirtual() {
|
||||
return vProps;
|
||||
}
|
||||
|
||||
int UserPropMgr::GetSelNodeCount() {
|
||||
if (vProps) return 1;
|
||||
else return ip->GetSelNodeCount();
|
||||
}
|
||||
INode *UserPropMgr::GetSelNode(int i) {
|
||||
if (vProps) return NULL;
|
||||
else return ip->GetSelNode(i);
|
||||
}
|
||||
|
||||
|
||||
void UserPropMgr::OpenQuickTable()
|
||||
{
|
||||
if (!fQuickTable)
|
||||
{
|
||||
fQuickTable = TRACKED_NEW hsHashTable<QuickPair>(kQuickSize);
|
||||
}
|
||||
fQuickNode = nil;
|
||||
}
|
||||
|
||||
void UserPropMgr::CloseQuickTable()
|
||||
{
|
||||
#ifdef HS_DEBUGGING
|
||||
if (fQuickNode && fQuickTable)
|
||||
{
|
||||
char str[256];
|
||||
sprintf(str,"%d Hash Collisions reported\n",fQuickTable->CollisionCount());
|
||||
hsStatusMessage(str);
|
||||
}
|
||||
#endif
|
||||
|
||||
delete fQuickTable;
|
||||
fQuickTable = nil;
|
||||
fQuickNode = nil;
|
||||
QuickPair::SetBuffer(nil);
|
||||
}
|
||||
|
||||
void UserPropMgr::IBuildQuickTable(INode* node)
|
||||
{
|
||||
if (fQuickTable && fQuickNode != node)
|
||||
{
|
||||
fQuickNode = node;
|
||||
|
||||
// clear old QuickTable
|
||||
fQuickTable->clear();
|
||||
|
||||
// build new one
|
||||
TSTR buf;
|
||||
GetUserPropBuffer(node,buf);
|
||||
|
||||
hsStringTokenizer toker(buf," \r\n");
|
||||
toker.ParseQuotes(TRUE);
|
||||
|
||||
char *tok;
|
||||
bool inName = false;
|
||||
bool isName = true;
|
||||
while ( inName || (tok=toker.next()) )
|
||||
{
|
||||
if (isName)
|
||||
{
|
||||
if (*tok != '=')
|
||||
{
|
||||
QuickPair qPair;
|
||||
qPair.SetKey(tok);
|
||||
|
||||
tok = toker.next();
|
||||
if (tok && *tok == '=')
|
||||
{
|
||||
tok = toker.next();
|
||||
qPair.SetVal(tok);
|
||||
|
||||
inName = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
qPair.SetVal(nil);
|
||||
inName = (tok != 0);
|
||||
}
|
||||
|
||||
fQuickTable->insert(qPair);
|
||||
}
|
||||
else
|
||||
{
|
||||
isName = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
isName = true;
|
||||
}
|
||||
}
|
||||
|
||||
// QuickPair owns the tok'd buffer now
|
||||
QuickPair::SetBuffer(toker.fString);
|
||||
toker.fString = nil;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL UserPropMgr::ICheckQuickEntry(const char *key, TSTR &value)
|
||||
{
|
||||
QuickPair q;
|
||||
q.SetKey(key);
|
||||
hsHashTableIterator<QuickPair> it = fQuickTable->find(q);
|
||||
return it->GetVal(value);
|
||||
}
|
||||
|
||||
|
||||
char* UserPropMgr::QuickPair::fBuffer = nil;
|
||||
|
||||
void UserPropMgr::QuickPair::SetBuffer(char* buf)
|
||||
{
|
||||
delete [] fBuffer;
|
||||
fBuffer = buf;
|
||||
}
|
||||
|
||||
UInt32 UserPropMgr::QuickPair::GetHash() const
|
||||
{
|
||||
const char * k = fKey;
|
||||
int len = k ? strlen(k) : 0;
|
||||
int h;
|
||||
for (h=len; len--;)
|
||||
{
|
||||
h = ((h<<5)^(h>>27))^tolower(*k++);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
hsBool UserPropMgr::QuickPair::GetVal(TSTR& value)
|
||||
{
|
||||
if (fKey)
|
||||
{
|
||||
value = fVal ? fVal : "";
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool UserPropMgr::QuickPair::operator==(const QuickPair& other) const
|
||||
{
|
||||
return !_stricmp(fKey,other.fKey);
|
||||
}
|
159
Sources/Tools/MaxConvert/UserPropMgr.h
Normal file
159
Sources/Tools/MaxConvert/UserPropMgr.h
Normal file
@ -0,0 +1,159 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
// UserPropMgr
|
||||
|
||||
#ifndef _USERPROPMGR_H_
|
||||
#define _USERPROPMGR_H_
|
||||
|
||||
#include "Max.h"
|
||||
#include "hsTypes.h"
|
||||
|
||||
template <class T> class hsHashTable;
|
||||
|
||||
class UserPropMgr {
|
||||
public:
|
||||
enum
|
||||
{
|
||||
kMe = 0,
|
||||
kParent,
|
||||
kRoot
|
||||
};
|
||||
|
||||
UserPropMgr(); // No Default Constructor!
|
||||
UserPropMgr(Interface *ip);
|
||||
~UserPropMgr();
|
||||
|
||||
NameMaker *nm;
|
||||
|
||||
void SetUserPropFlag(INode *node, const char *name, const BOOL setFlag, const Int32 hFlag=kMe);
|
||||
|
||||
void SelectUserPropFlagALL(INode *node, const char *name, const BOOL flag);
|
||||
void ClearUserProp(INode *node, const char *name, const Int32 hFlag=kMe);
|
||||
void ClearUserPropALL(const char *name, const Int32 hFlag=kMe);
|
||||
void SetUserPropFlagALL(const char *name, const BOOL setFlag, const Int32 hFlag=kMe);
|
||||
BOOL GetUserPropFlagALL(const char *name, BOOL &isSet, const Int32 hFlag=kMe);
|
||||
|
||||
BOOL GetUserProp(INode *node, const char *name, TSTR &value, const Int32 hFlag=kMe);
|
||||
void SetUserProp(INode *node, const char *name, const char *value, const Int32 hFlag=kMe);
|
||||
BOOL UserPropExists(INode *node, const char *name, const Int32 hFlag=kMe);
|
||||
|
||||
BOOL GetUserPropString(INode *node, const char *name, TSTR &value, const Int32 hFlag=kMe);
|
||||
void SetUserPropString(INode *node, const char *name, const char *value, const Int32 hFlag=kMe);
|
||||
BOOL GetUserPropFloat(INode *node, const char *name, float &value, const Int32 hFlag=kMe);
|
||||
void SetUserPropFloat(INode *node, const char *name, const float value, const Int32 hFlag=kMe);
|
||||
BOOL GetUserPropInt(INode *node, const char *name, int &value, const Int32 hFlag=kMe);
|
||||
void SetUserPropInt(INode *node, const char *name, const int value, const Int32 hFlag=kMe);
|
||||
BOOL GetUserPropStringList(INode *node, const char *name, int &num, TSTR list[]);
|
||||
BOOL GetUserPropIntList(INode *node, const char *name, int &num, int list[]);
|
||||
BOOL GetUserPropFloatList(INode *node, const char *name, int &num, float list[]);
|
||||
|
||||
BOOL GetUserPropStringALL(const char *name, TSTR &value, const Int32 hFlag=kMe);
|
||||
void SetUserPropStringALL(const char *name, const char *value, const Int32 hFlag=kMe);
|
||||
BOOL GetUserPropStringListALL(const char *name, int &num, TSTR list[]);
|
||||
BOOL GetUserPropIntListALL(const char *name, int &num, int *list);
|
||||
BOOL GetUserPropFloatListALL(const char *name, int &num, float *list);
|
||||
|
||||
BOOL GetNodeNameALL(TSTR &name);
|
||||
void SetNodeNameALL(const char *name);
|
||||
|
||||
void LoadVirtualProps(BOOL reset=true);
|
||||
void DestroyVirtualProps();
|
||||
BOOL IsVirtual();
|
||||
|
||||
int GetSelNodeCount();
|
||||
INode *GetSelNode(int i);
|
||||
|
||||
int GetUserPropCount(INode *node);
|
||||
void GetUserPropBuffer(INode *node, TSTR &buf);
|
||||
void SetUserPropBuffer(INode *node, const TSTR &buf);
|
||||
|
||||
BOOL IsAlike(INode *node, BOOL MatchAll=true);
|
||||
int CountAlike(BOOL MatchAll=true);
|
||||
void DeSelectUnAlike(INode *node=NULL);
|
||||
|
||||
Interface *GetInterface() { return ip; }
|
||||
|
||||
void OpenQuickTable();
|
||||
void CloseQuickTable();
|
||||
|
||||
private:
|
||||
INode* GetAncestorIfNeeded(INode* node, const Int32 hFlag);
|
||||
void DeSelectWithOut(const char *name, const char *value);
|
||||
void RecursiveSelectAll(INode *node = NULL);
|
||||
int RecursiveCountAlike(INode *node = NULL, BOOL MatchAll=true);
|
||||
BOOL IsMatch(const char *val1, const char *val2);
|
||||
BOOL vProps;
|
||||
TSTR vbuf;
|
||||
TSTR vname;
|
||||
|
||||
class QuickPair
|
||||
{
|
||||
public:
|
||||
static void SetBuffer(char* buf);
|
||||
protected:
|
||||
static char* fBuffer;
|
||||
const char* fKey;
|
||||
const char* fVal;
|
||||
public:
|
||||
QuickPair() : fKey(nil), fVal(nil) { }
|
||||
~QuickPair() { }
|
||||
|
||||
void SetKey(const char* k) { fKey = k; }
|
||||
void SetVal(const char* v) { fVal = v; }
|
||||
|
||||
UInt32 GetHash() const;
|
||||
|
||||
hsBool GetVal(TSTR& value);
|
||||
|
||||
bool operator==(const QuickPair& other) const;
|
||||
};
|
||||
hsHashTable<QuickPair>* fQuickTable;
|
||||
static const UInt32 kQuickSize;
|
||||
INode* fQuickNode;
|
||||
void IBuildQuickTable(INode* node);
|
||||
BOOL ICheckQuickEntry(const char *key, TSTR &value);
|
||||
|
||||
Interface *ip;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
2169
Sources/Tools/MaxConvert/hsControlConverter.cpp
Normal file
2169
Sources/Tools/MaxConvert/hsControlConverter.cpp
Normal file
File diff suppressed because it is too large
Load Diff
201
Sources/Tools/MaxConvert/hsControlConverter.h
Normal file
201
Sources/Tools/MaxConvert/hsControlConverter.h
Normal file
@ -0,0 +1,201 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
#ifndef __HSCONTROLCONVERTER_H
|
||||
#define __HSCONTROLCONVERTER_H
|
||||
|
||||
#include <commdlg.h>
|
||||
#include <math.h>
|
||||
|
||||
//#include "Max.h"
|
||||
#include "stdmat.h"
|
||||
#include "bmmlib.h"
|
||||
#include "istdplug.h"
|
||||
#include "texutil.h"
|
||||
#include "../../../Sources/Plasma/PubUtilLib/plInterp/hsKeys.h"
|
||||
#include "hsTemplates.h"
|
||||
|
||||
class plMaxNode;
|
||||
|
||||
enum ControllerType
|
||||
{
|
||||
ctrlTypeUnknown,
|
||||
ctrlTypeFloat,
|
||||
ctrlTypePoint3,
|
||||
ctrlTypePosition,
|
||||
ctrlTypeRotation,
|
||||
ctrlTypeRotationX,
|
||||
ctrlTypeRotationY,
|
||||
ctrlTypeRotationZ,
|
||||
ctrlTypeScale,
|
||||
ctrlTypeTransform,
|
||||
ctrlTypeEase,
|
||||
ctrlTypeMult,
|
||||
ctrlTypeVert, // CS Biped
|
||||
ctrlTypeHoriz, // CS Biped
|
||||
ctrlTypeTurn, // CS Biped
|
||||
ctrlTypeRollAngle,
|
||||
};
|
||||
|
||||
class plController;
|
||||
class plLeafController;
|
||||
class plCompoundController;
|
||||
struct hsKeyFrame;
|
||||
class hsConverterUtils;
|
||||
class plSceneObject;
|
||||
|
||||
class hsControlConverter
|
||||
{
|
||||
private:
|
||||
hsControlConverter();
|
||||
|
||||
public:
|
||||
~hsControlConverter() { };
|
||||
static hsControlConverter& Instance();
|
||||
|
||||
void Init(plErrorMsg* msg);
|
||||
void DeInit();
|
||||
|
||||
// Used to pick correct controller by lights/materials
|
||||
hsBool GetControllerByName(Animatable* anim, TSTR &name, Control* &ctl);
|
||||
Control *GetControllerByID(IParamBlock2 *pblock, int paramID);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Controller convert functions:
|
||||
//
|
||||
// All convert functions must call ISetSegRange(start, end) at the beginning.
|
||||
// (ISetSegRange(-1, -1) will give you the entire anim.)
|
||||
plLeafController* MakeMatrix44Controller(StdUVGen* uvGen, const char* nodeName);
|
||||
plLeafController* MakeMatrix44Controller(Control* prsControl);
|
||||
plLeafController* MakeScalarController(Control* control, plMaxNode* node, hsScalar start = -1, hsScalar end = -1);
|
||||
plController* MakeColorController(Control* control, plMaxNode* node, hsScalar start = -1, hsScalar end = -1);
|
||||
plController* MakePosController(Control* control, plMaxNode* node, hsScalar start = -1, hsScalar end = -1);
|
||||
plController* MakeScaleController(Control* control, plMaxNode* node, hsScalar start = -1, hsScalar end = -1);
|
||||
plController* MakeRotController(Control* control, plMaxNode* node, hsBool camRot = false, hsScalar start = -1, hsScalar end = -1);
|
||||
plCompoundController* MakeTransformController(Control* control, plMaxNode* node, hsScalar start = -1, hsScalar end = -1);
|
||||
|
||||
// This last one was in tempAnim.cpp on its own for some time, apparently created
|
||||
// as an initial attempt to get anims working in Max. It's still used, so I don't want
|
||||
// to nuke it, but it made sense to move it here.
|
||||
plController* ConvertTMAnim(plSceneObject *obj, plMaxNode *node, hsAffineParts *parts, hsScalar start = -1, hsScalar end = -1);
|
||||
//
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Matrix3ToHsMatrix44(Matrix3* m3, hsMatrix44* hsM);
|
||||
Matrix3 StdUVGenToMatrix3(StdUVGen* uvGen);
|
||||
bool StdUVGenToHsMatrix44(hsMatrix44* hsMat, StdUVGen* uvGen, bool preserveOffset=false);
|
||||
void MaxSampleAngles(const char* nodeName, Control* ctl, Tab<TimeValue>& kTimes, hsScalar maxRads);
|
||||
void ScalePositionController(plController* ctl, hsScalar scale);
|
||||
|
||||
void ReduceKeys(Control *control, hsScalar threshold);
|
||||
hsBool HasKeyTimes(Control* ctl);
|
||||
UInt8 GetKeyType(Control* ctl, hsBool rotQuat = false);
|
||||
|
||||
plMaxNode* GetXformParent(plMaxNode* node);
|
||||
hsBool ForceWorldSpace(plMaxNode* node);
|
||||
hsBool ForceOrigin(plMaxNode* node);
|
||||
hsBool ForceLocal(plMaxNode* node);
|
||||
hsBool IsAnimated(plMaxNode* node);
|
||||
hsBool OwnsMaterialCopy(plMaxNode* node);
|
||||
hsBool HasFrameEvents(plMaxNode *node);
|
||||
|
||||
void CompositeKeyTimes(Control* ctl, Tab<TimeValue> &time);
|
||||
|
||||
int GetTicksPerFrame() { return fTicksPerFrame; }
|
||||
int GetFrameRate() { return fFrameRate; }
|
||||
int GetTicksPerSec() { return fTicksPerSec; }
|
||||
int GetStartFrame() { return fStartFrame; }
|
||||
int GetEndFrame() { return fEndFrame; }
|
||||
int GetNumFrames() { return fNumFrames; }
|
||||
float GetAnimLength() { return fAnimLength; }
|
||||
|
||||
private:
|
||||
void ISetSegRange(hsScalar start, hsScalar end);
|
||||
void IConvertSubTransform(Control *control, char *ctlName, plMaxNode *node, plCompoundController *tmc, hsScalar start, hsScalar end);
|
||||
|
||||
plLeafController* ICreateSimpleRotController(plMaxNode* node, Control* control, hsBool camRot = false);
|
||||
plLeafController* ICreateSimpleScaleController(plMaxNode* node, Control* control);
|
||||
plLeafController* ICreateQuatController(plMaxNode* node, Control* control, bool rotation = true, hsBool camRot = false);
|
||||
plLeafController* ICreateScaleValueController(plMaxNode* node, Control* control);
|
||||
plLeafController* ICreateScalarController(plMaxNode* node, Control* control);
|
||||
plLeafController* ICreateSimplePosController(plMaxNode* node, Control* control);
|
||||
|
||||
void IEnableEaseCurves(Animatable* control, bool enable);
|
||||
void IGetControlSampleTimes(Control* control, int iLo, int iHi, Tab<TimeValue>& kTimes, float maxRads);
|
||||
int IAddPartsKeys(Control* control, hsTArray <hsG3DSMaxKeyFrame>* kfArray, plMaxNode* node);
|
||||
Int32 ICreateHSInterpKey(Control* control, IKey* mKey, TimeValue keyTime, hsKeyFrame* baseKey, plMaxNode* node=nil, hsBool rotQuat = false);
|
||||
Int32 IGetRangeCoverKeyIndices(char* nodeName, Control* cont, Int32 &start, Int32 &end);
|
||||
ControllerType IGetControlType(TSTR ctrlName);
|
||||
bool IIsKeyTimeInRange(TimeValue time);
|
||||
bool IIsKeyInRange(IKey* key);
|
||||
void IGetUnEasedLocalTM(plMaxNode* node, Control* control, hsMatrix44* out, TimeValue time);
|
||||
Matrix3 IFlipY();
|
||||
bool ISkinNode(plMaxNode* node);
|
||||
void ISetForceLocal(bool f) { fForceLocal=f; }
|
||||
|
||||
hsBool IGetEditableMeshKeyTimes( plMaxNode *node, Tab<TimeValue> × );
|
||||
hsBool IGetGeomKeyTimes( plMaxNode *node, Tab<TimeValue> × );
|
||||
void IGetGeomKeyTimesRecur( Animatable *anim, Tab<TimeValue> × );
|
||||
hsBool IGetSubAnimByName( Animatable *anim, TSTR &name, Animatable *&subAnim );
|
||||
void IExportAnimatedCameraFOV(plMaxNode* node, hsTArray <hsG3DSMaxKeyFrame>* kfArray);
|
||||
Interface* fInterface;
|
||||
|
||||
hsConverterUtils& fConverterUtils;
|
||||
plErrorMsg * fErrorMsg;
|
||||
|
||||
Int32 fTicksPerFrame;
|
||||
Int32 fFrameRate;
|
||||
Int32 fTicksPerSec;
|
||||
Int32 fStartFrame;
|
||||
Int32 fEndFrame;
|
||||
Int32 fNumFrames;
|
||||
hsScalar fAnimLength;
|
||||
hsBool fWarned;
|
||||
|
||||
hsBool fForceLocal;
|
||||
|
||||
TimeValue fSegStart;
|
||||
TimeValue fSegEnd;
|
||||
};
|
||||
|
||||
#endif
|
563
Sources/Tools/MaxConvert/hsConverterUtils.cpp
Normal file
563
Sources/Tools/MaxConvert/hsConverterUtils.cpp
Normal file
@ -0,0 +1,563 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#include "hsTypes.h"
|
||||
#include "hsConverterUtils.h"
|
||||
#include "hsResMgr.h"
|
||||
|
||||
#if HS_BUILD_FOR_WIN32
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "hsMaxLayerBase.h"
|
||||
#include "../plInterp/plController.h"
|
||||
|
||||
#include "../MaxExport/plErrorMsg.h"
|
||||
#include "UserPropMgr.h"
|
||||
#include "hsStringTokenizer.h"
|
||||
//#include "hsDXTDirectXCodec.h"
|
||||
//#include "hsDXTSoftwareCodec.h"
|
||||
#include "../plGImage/hsCodecManager.h"
|
||||
///#include "SwitchUtil.h"
|
||||
#include "hsExceptionStack.h"
|
||||
#include "hsHashTable.h"
|
||||
#include "../pnKeyedObject/plKey.h"
|
||||
#include "../pnKeyedObject/hsKeyedObject.h"
|
||||
|
||||
const char hsConverterUtils::fTagSeps[] = " ,\t\n=:;";
|
||||
|
||||
extern UserPropMgr gUserPropMgr;
|
||||
|
||||
namespace {
|
||||
class ObjectInstancedEnumProc : public DependentEnumProc
|
||||
{
|
||||
public:
|
||||
ObjectInstancedEnumProc() : fInstanceCount(0) { }
|
||||
|
||||
int proc(ReferenceMaker *rmaker)
|
||||
{
|
||||
hsGuardBegin("ObjectInstancedEnumProc::proc");
|
||||
|
||||
if (rmaker->SuperClassID()==BASENODE_CLASS_ID)
|
||||
{
|
||||
fInstanceCount++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
Int32 GetInstanceCount() { return fInstanceCount; }
|
||||
|
||||
private:
|
||||
Int32 fInstanceCount;
|
||||
};
|
||||
}
|
||||
|
||||
hsConverterUtils& hsConverterUtils::Instance()
|
||||
{
|
||||
static hsConverterUtils the_instance;
|
||||
|
||||
return the_instance;
|
||||
}
|
||||
|
||||
hsConverterUtils::hsConverterUtils() :
|
||||
fInterface(GetCOREInterface()),
|
||||
fErrorMsg(nil),
|
||||
fSuppressMangling(false),
|
||||
fWarned(0)
|
||||
{
|
||||
}
|
||||
|
||||
void hsConverterUtils::Init(hsBool save, plErrorMsg *msg)
|
||||
{
|
||||
hsGuardBegin("hsConverterUtils::Init");
|
||||
|
||||
fErrorMsg = msg;
|
||||
|
||||
fSuppressMangling = false;
|
||||
fWarned = 0;
|
||||
fSave = save;
|
||||
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
TimeValue hsConverterUtils::GetTime(Interface *gi)
|
||||
{
|
||||
hsGuardBegin("hsConverterUtils::GetTime");
|
||||
|
||||
return ((TimeValue)0);
|
||||
hsGuardEnd;
|
||||
// return gi->GetTime();
|
||||
// return theSceneEnum->time;
|
||||
}
|
||||
|
||||
hsBool hsConverterUtils::IsEnvironHolder(INode *node)
|
||||
{
|
||||
hsGuardBegin("hsConverterUtils::IsEnvironHolder");
|
||||
|
||||
return (gUserPropMgr.UserPropExists(node, "EnvironMap"));
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
hsBool hsConverterUtils::AutoStartDynamics(INode *node)
|
||||
{
|
||||
hsGuardBegin("hsConverterUtils::AutoStartDynamics");
|
||||
|
||||
return (gUserPropMgr.UserPropExists(node,"AutoStart") || gUserPropMgr.UserPropExists(node,"aud"));
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
hsBool hsConverterUtils::RandomStartDynamics(INode *node)
|
||||
{
|
||||
hsGuardBegin("hsConverterUtils::RandomStartDynamics");
|
||||
|
||||
return (gUserPropMgr.UserPropExists(node,"RandomStart"));
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
void hsConverterUtils::StripOffTail(char* path)
|
||||
{
|
||||
hsGuardBegin("hsConverterUtils::StripOffTail");
|
||||
|
||||
int i = strlen(path)-1;
|
||||
while(path[i] != '\\')
|
||||
i--;
|
||||
path[i+1] = 0;
|
||||
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
void hsConverterUtils::StripOffPath(char* fileName)
|
||||
{
|
||||
hsGuardBegin("hsConverterUtils::StripOffPath");
|
||||
|
||||
char tmp[256];
|
||||
// Remove preceding path
|
||||
int i = strlen(fileName)-1;
|
||||
while(fileName[i] != '\\')
|
||||
i--;
|
||||
strcpy(tmp, fileName+i+1);
|
||||
strcpy(fileName, tmp);
|
||||
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
//
|
||||
// static
|
||||
//
|
||||
hsBool hsConverterUtils::IsReservedKeyword(const char* nodeName)
|
||||
{
|
||||
hsGuardBegin("hsConverterUtils::IsReservedKeyword");
|
||||
|
||||
return (nodeName!=nil &&
|
||||
( !_stricmp(nodeName, "theplayer")
|
||||
|| !_stricmp(nodeName, "the_player")
|
||||
|| !_stricmp(nodeName, "thecamera")
|
||||
|| !_stricmp(nodeName, "the_camera")
|
||||
|| !_stricmp(nodeName, "thedetector")
|
||||
|| !_stricmp(nodeName, "the_detector")
|
||||
|| !_stricmp(nodeName, "themonitor")
|
||||
|| !_stricmp(nodeName, "the_monitor")
|
||||
|| !_stricmp(nodeName, "thedetectorshape")
|
||||
|| !_stricmp(nodeName, "the_detector_shape")) );
|
||||
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
char *hsConverterUtils::MangleReference(char *mangName, const char *nodeName, const char* defRoom)
|
||||
{
|
||||
hsGuardBegin("hsConverterUtils::MangleReference");
|
||||
|
||||
//hsAssert(nodeName, "No node name in hsConverterUtils::MangleReference.");
|
||||
if(!nodeName)
|
||||
{
|
||||
fErrorMsg->Set(true, "Mangle Reference Error", "No node name in hsConverterUtils::MangleReference.").Show();
|
||||
fErrorMsg->Set();
|
||||
return mangName;
|
||||
}
|
||||
if (!*nodeName)
|
||||
return hsStrcpy(mangName, nodeName);
|
||||
|
||||
// doesn't want to be mangled
|
||||
if (('.' == nodeName[0])&&('.' == nodeName[1]))
|
||||
return hsStrcpy(mangName, nodeName + 2);
|
||||
|
||||
// already mangled or reserved
|
||||
if (strstr(nodeName, "..") || IsReservedKeyword(nodeName))
|
||||
return hsStrcpy(mangName, nodeName);
|
||||
|
||||
INode *node = GetINodeByName(nodeName);
|
||||
|
||||
if (!node)
|
||||
{
|
||||
// no room so make global
|
||||
// Default is to make it global, but you can set another default (like same
|
||||
// room as referencer) with defRoom.
|
||||
char tempName[256];
|
||||
|
||||
sprintf(tempName, "%s..%s", defRoom, nodeName);
|
||||
return hsStrcpy(mangName, tempName);
|
||||
}
|
||||
|
||||
return MangleReference(mangName, node);
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
char *hsConverterUtils::MangleReference(char *mangName, INode *node, const char* defRoom)
|
||||
{
|
||||
hsGuardBegin("hsConverterUtils::MangleReference");
|
||||
|
||||
if (!node)
|
||||
return nil;
|
||||
|
||||
char tempName[256];
|
||||
|
||||
char *nodeName = node->GetName();
|
||||
char *roomName = nil;
|
||||
TSTR sdata;
|
||||
hsStringTokenizer toker;
|
||||
if (gUserPropMgr.GetUserPropString(node, "Rooms", sdata))
|
||||
{
|
||||
toker.Reset(sdata, fTagSeps);
|
||||
roomName = toker.next();
|
||||
}
|
||||
|
||||
if (fSuppressMangling)
|
||||
{
|
||||
return hsStrcpy(mangName, nodeName);
|
||||
}
|
||||
|
||||
if (('.' == nodeName[0])&&('.' == nodeName[1]))
|
||||
hsStrcpy(tempName, nodeName + 2);
|
||||
else if (!*nodeName
|
||||
|| strstr(nodeName, "..")
|
||||
|| IsReservedKeyword(nodeName)
|
||||
)
|
||||
hsStrcpy(tempName, nodeName);
|
||||
else if (roomName && *roomName)
|
||||
sprintf(tempName, "%s..%s", roomName, nodeName);
|
||||
else
|
||||
sprintf(tempName, "%s..%s", defRoom, nodeName);
|
||||
|
||||
return hsStrcpy(mangName, tempName);
|
||||
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
char *hsConverterUtils::MangleRefWithRoom(char *mangName, const char *nodeName, const char* roomName)
|
||||
{
|
||||
hsGuardBegin("hsConverterUtils::MangleRefWithRoom");
|
||||
|
||||
//hsAssert(nodeName && roomName, "No node or room name in hsConverterUtils::MangleRefWithRoom.");
|
||||
if(!(nodeName && roomName))
|
||||
{
|
||||
fErrorMsg->Set(true, "Mangle Room Reference Error", "No node or room name in hsConverterUtils::MangleRefWithRoom.").Show();
|
||||
fErrorMsg->Set();
|
||||
return mangName;
|
||||
}
|
||||
|
||||
if (!*nodeName)
|
||||
return hsStrcpy(mangName,nodeName);
|
||||
|
||||
// doesn't want to be mangled
|
||||
if (('.' == nodeName[0])&&('.' == nodeName[1]))
|
||||
return hsStrcpy(mangName, nodeName + 2);
|
||||
|
||||
// already mangled or reserved
|
||||
if (strstr(nodeName, "..") || IsReservedKeyword(nodeName))
|
||||
return hsStrcpy(mangName, nodeName);
|
||||
|
||||
sprintf(mangName, "%s..%s", roomName, nodeName);
|
||||
return mangName;
|
||||
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
|
||||
INode* hsConverterUtils::FindINodeFromMangledName(const char* mangName)
|
||||
{
|
||||
hsGuardBegin("hsConverterUtils::FindINodeFromMangledName");
|
||||
|
||||
if( !(mangName && *mangName) )
|
||||
return nil;
|
||||
|
||||
const char* nodeName = mangName;
|
||||
|
||||
char* p;
|
||||
while( p = strstr(nodeName, "..") )
|
||||
{
|
||||
nodeName = p + 2;
|
||||
}
|
||||
if( !(nodeName && *nodeName) )
|
||||
nodeName = mangName;
|
||||
|
||||
return GetINodeByName(nodeName);
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
INode* hsConverterUtils::FindINodeFromKeyedObject(hsKeyedObject* obj)
|
||||
{
|
||||
hsGuardBegin("hsConverterUtils::FindINodeFromKeyedObject");
|
||||
|
||||
INode* retVal = FindINodeFromMangledName(obj->GetKey()->GetName());
|
||||
if( retVal )
|
||||
return (retVal);
|
||||
|
||||
/* No more other Keys plasma 2.0
|
||||
int i;
|
||||
for( i = 0; i < obj->GetNumOtherKeys(); i++ )
|
||||
{
|
||||
retVal = FindINodeFromMangledName(obj->GetOtherKey(i)->GetName());
|
||||
if( retVal )
|
||||
return retVal;
|
||||
}
|
||||
*/
|
||||
return nil;
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
// Uses MangleRef so all mangling happens in one place. Compares the name with a mangled version of it
|
||||
hsBool hsConverterUtils::IsMangled(const char *name)
|
||||
{
|
||||
hsGuardBegin("hsConverterUtils::IsMangled");
|
||||
|
||||
char mang[255];
|
||||
return !strcmp(name,MangleReference(mang,name));
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
// Undoes the process of mangling. This includes taking a "name" back to "..name"
|
||||
char *hsConverterUtils::UnMangleReference(char *dest, const char *name)
|
||||
{
|
||||
hsGuardBegin("hsConverterUtils::IsMangled");
|
||||
|
||||
char *u = strstr(name,"..");
|
||||
if (u)
|
||||
{
|
||||
u+=2;
|
||||
strcpy(dest,u);
|
||||
}
|
||||
else if (!IsMangled(name))
|
||||
{
|
||||
strcpy(dest,"..");
|
||||
strcat(dest,name);
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(dest,name);
|
||||
}
|
||||
|
||||
return dest;
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
// Similar to UnMangle but doesn't take "name" back to "..name"
|
||||
char* hsConverterUtils::StripMangledReference(char* dest, const char* name)
|
||||
{
|
||||
hsGuardBegin("hsConverterUtils::StripMangledReference");
|
||||
|
||||
char *u = strstr(name,"..");
|
||||
if (u)
|
||||
{
|
||||
u+=2;
|
||||
strcpy(dest,u);
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(dest,name);
|
||||
}
|
||||
|
||||
return dest;
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
Int32 hsConverterUtils::FindNamedSelSetFromName(const char *name)
|
||||
{
|
||||
hsGuardBegin("hsConverterUtils::FindNamedSelSetFromName");
|
||||
|
||||
for (Int32 i=0; i<fInterface->GetNumNamedSelSets(); i++)
|
||||
{
|
||||
if (!_stricmp(name, fInterface->GetNamedSelSetName(i)))
|
||||
return (i);
|
||||
}
|
||||
|
||||
return (-1);
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
hsBool hsConverterUtils::IsInstanced(Object* maxObject)
|
||||
{
|
||||
hsGuardBegin("hsConverterUtils::IsInstanced");
|
||||
|
||||
if (!maxObject)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ObjectInstancedEnumProc instProc;
|
||||
maxObject->EnumDependents(&instProc);
|
||||
|
||||
return (instProc.GetInstanceCount() > 1);
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
|
||||
INode* hsConverterUtils::IGetINodeByNameRecur(INode* node, const char* wantName)
|
||||
{
|
||||
hsGuardBegin("hsConverterUtils::IGetINodeByNameRecur");
|
||||
|
||||
if (!node || !node->GetName())
|
||||
return nil;
|
||||
|
||||
char* nodeName=node->GetName();
|
||||
if (!_stricmp(nodeName, wantName))
|
||||
return node;
|
||||
|
||||
// Process children
|
||||
int num = node->NumberOfChildren();
|
||||
int i;
|
||||
for(i=0; i<num; i++)
|
||||
{
|
||||
INode* ret;
|
||||
if ((ret=IGetINodeByNameRecur(node->GetChildNode(i), wantName)))
|
||||
return ret;
|
||||
}
|
||||
|
||||
return nil;
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
//
|
||||
// Matches name against node's name, case-insensitive,
|
||||
//
|
||||
INode* hsConverterUtils::GetINodeByName(const char* name, hsBool caseSensitive)
|
||||
{
|
||||
hsGuardBegin("hsConverterUtils::GetINodeByName");
|
||||
|
||||
if (!name)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (fNodeSearchCache)
|
||||
{
|
||||
CacheNode cNode(name);
|
||||
cNode.SetCaseSensitive(caseSensitive);
|
||||
hsHashTableIterator<CacheNode> it = fNodeSearchCache->find(cNode);
|
||||
return it->GetNode();
|
||||
}
|
||||
|
||||
//hsAssert(fInterface, "nil fInterface in hsConverterUtils::GetINodeByName()");
|
||||
if(!fInterface)
|
||||
{
|
||||
fErrorMsg->Set(true, "Get INode by Name Error", "nil fInterface in hsConverterUtils::GetINodeByName()").Show();
|
||||
fErrorMsg->Set();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
if (caseSensitive)
|
||||
{
|
||||
return fInterface->GetINodeByName(name);
|
||||
}
|
||||
|
||||
return IGetINodeByNameRecur(fInterface->GetRootNode(), name);
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
void hsConverterUtils::CreateNodeSearchCache()
|
||||
{
|
||||
if (!fNodeSearchCache)
|
||||
{
|
||||
fNodeSearchCache = TRACKED_NEW hsHashTable<CacheNode>();
|
||||
}
|
||||
fNodeSearchCache->clear();
|
||||
|
||||
IBuildNodeSearchCacheRecur(fInterface->GetRootNode());
|
||||
}
|
||||
|
||||
void hsConverterUtils::DestroyNodeSearchCache()
|
||||
{
|
||||
delete fNodeSearchCache;
|
||||
fNodeSearchCache = nil;
|
||||
}
|
||||
|
||||
void hsConverterUtils::IBuildNodeSearchCacheRecur(INode* node)
|
||||
{
|
||||
if (!node || !node->GetName())
|
||||
return ;
|
||||
|
||||
CacheNode cNode(node);
|
||||
fNodeSearchCache->insert(cNode);
|
||||
|
||||
// Process children
|
||||
int num = node->NumberOfChildren();
|
||||
int i;
|
||||
for(i=0; i<num; i++)
|
||||
{
|
||||
IBuildNodeSearchCacheRecur(node->GetChildNode(i));
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 hsConverterUtils::CacheNode::GetHash() const
|
||||
{
|
||||
const char* k = GetName();
|
||||
int len = k ? strlen(k) : 0;
|
||||
for (int h=len; len--;)
|
||||
{
|
||||
h = ((h<<5)^(h>>27))^tolower(*k++);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
bool hsConverterUtils::CacheNode::operator==(const CacheNode& other) const
|
||||
{
|
||||
const char* k1 = GetName();
|
||||
const char* k2 = other.GetName();
|
||||
if (other.fCaseSensitive || fCaseSensitive)
|
||||
return !strcmp(k1,k2);
|
||||
else
|
||||
return !_stricmp(k1,k2);
|
||||
}
|
||||
|
||||
#endif // HS_BUILD_FOR_WIN32
|
151
Sources/Tools/MaxConvert/hsConverterUtils.h
Normal file
151
Sources/Tools/MaxConvert/hsConverterUtils.h
Normal file
@ -0,0 +1,151 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
#ifndef __HSCONVERTERUTILS_H
|
||||
#define __HSCONVERTERUTILS_H
|
||||
|
||||
#include "Max.h"
|
||||
#include "stdmat.h"
|
||||
#include <commdlg.h>
|
||||
#include "bmmlib.h"
|
||||
#include "istdplug.h"
|
||||
#include "texutil.h"
|
||||
|
||||
#include "Headspin.h"
|
||||
|
||||
class INode;
|
||||
class Control;
|
||||
class Interface;
|
||||
template <class T> class hsHashTable;
|
||||
|
||||
class hsMaxLayerBase;
|
||||
class plSimplePosController;
|
||||
class plScalarController;
|
||||
class plLeafController;
|
||||
class hsGBitmapClass;
|
||||
class hsGMipmapClass;
|
||||
class plErrorMsg;
|
||||
class hsKeyedObject;
|
||||
class hsGRenderProcs;
|
||||
class hsBaseRenderProc;
|
||||
|
||||
class hsConverterUtils
|
||||
{
|
||||
private:
|
||||
hsConverterUtils();
|
||||
public: // MSDEV bug
|
||||
~hsConverterUtils() {}
|
||||
public:
|
||||
static hsConverterUtils& Instance();
|
||||
static hsBool IsReservedKeyword(const char* nodeName);
|
||||
|
||||
void Init(hsBool save, plErrorMsg *msg);
|
||||
hsBool IsEnvironHolder(INode *node);
|
||||
hsBool AutoStartDynamics(INode *node);
|
||||
hsBool RandomStartDynamics(INode *node);
|
||||
TimeValue GetTime(Interface *gi);
|
||||
void StripOffTail(char* path);
|
||||
void StripOffPath(char* fileName);
|
||||
|
||||
INode* FindINodeFromKeyedObject(hsKeyedObject* obj);
|
||||
INode* FindINodeFromMangledName(const char* mangName);
|
||||
#if 0
|
||||
void MangleRPRefs(hsBaseRenderProc* base, hsGRenderProcs* rp);
|
||||
#endif
|
||||
char* MangleReference(char *mangName, const char *nodeName, const char* defRoom="global");
|
||||
char* MangleReference(char *mangName, INode *node, const char* defRoom="global");
|
||||
char* MangleRefWithRoom(char *mangName, const char *nodeName, const char* roomName);
|
||||
char* UnMangleReference(char *dest, const char *name);
|
||||
hsBool IsMangled(const char *name);
|
||||
Int32 FindNamedSelSetFromName(const char *name);
|
||||
char* StripMangledReference(char* dest, const char* name);
|
||||
|
||||
hsBool IsInstanced(Object* maxObject);
|
||||
|
||||
void CreateNodeSearchCache();
|
||||
void DestroyNodeSearchCache();
|
||||
INode* GetINodeByName(const char* name, hsBool caseSensitive=false);
|
||||
|
||||
static const char fTagSeps[];
|
||||
|
||||
private:
|
||||
|
||||
void IBuildNodeSearchCacheRecur(INode* node);
|
||||
INode* IGetINodeByNameRecur(INode* node, const char* wantName);
|
||||
|
||||
private:
|
||||
enum {
|
||||
kWarnedNoMoreBitmapLoadErr = 0x1
|
||||
};
|
||||
|
||||
Interface *fInterface;
|
||||
plErrorMsg *fErrorMsg;
|
||||
|
||||
hsBool fSuppressMangling;
|
||||
UInt32 fWarned;
|
||||
hsBool fSave;
|
||||
|
||||
struct CacheNode
|
||||
{
|
||||
private:
|
||||
INode* fNode;
|
||||
const char* fName;
|
||||
hsBool fCaseSensitive;
|
||||
public:
|
||||
CacheNode(INode* node=nil) : fNode(node), fName(nil), fCaseSensitive(false) { }
|
||||
CacheNode(const char* name) : fName(name), fNode(nil), fCaseSensitive(false) { }
|
||||
~CacheNode() { }
|
||||
|
||||
INode* GetNode() { return fNode; }
|
||||
const char* GetName() const { return fNode ? fNode->GetName() : fName; }
|
||||
|
||||
void SetCaseSensitive(hsBool b) { fCaseSensitive = b; }
|
||||
hsBool GetCaseSensitive() { return fCaseSensitive; }
|
||||
|
||||
UInt32 GetHash() const;
|
||||
bool operator==(const CacheNode& other) const;
|
||||
};
|
||||
hsHashTable<CacheNode>* fNodeSearchCache;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
5168
Sources/Tools/MaxConvert/hsMaterialConverter.cpp
Normal file
5168
Sources/Tools/MaxConvert/hsMaterialConverter.cpp
Normal file
File diff suppressed because it is too large
Load Diff
367
Sources/Tools/MaxConvert/hsMaterialConverter.h
Normal file
367
Sources/Tools/MaxConvert/hsMaterialConverter.h
Normal file
@ -0,0 +1,367 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
#ifndef __HSMATERIALCONVERTER_H
|
||||
#define __HSMATERIALCONVERTER_H
|
||||
|
||||
#include "HeadSpin.h"
|
||||
#include "hsTemplates.h"
|
||||
|
||||
#include "Max.h"
|
||||
|
||||
class Interface;
|
||||
|
||||
class hsStream;
|
||||
class hsScene;
|
||||
class hsGMaterial;
|
||||
class plLayer;
|
||||
class plLayerInterface;
|
||||
class hsGBitmapClass;
|
||||
class hsGQTLayer;
|
||||
class hsGAVILayer;
|
||||
class hsGBinkLayer;
|
||||
class hsConverterUtils;
|
||||
class hsGAnimLayer;
|
||||
class plBitmap;
|
||||
class plMipmap;
|
||||
class plErrorMsg;
|
||||
|
||||
class Mtl;
|
||||
class Texmap;
|
||||
class plMaxNode;
|
||||
class StdUVGen;
|
||||
class BitmapTex;
|
||||
class StdMat;
|
||||
class TSTR;
|
||||
class Animatable;
|
||||
class Bitmap;
|
||||
class plLocation;
|
||||
|
||||
class plLayerTex;
|
||||
class plBitmapData;
|
||||
class plCubicRenderTarget;
|
||||
class plStaticEnvLayer;
|
||||
class plDynamicEnvLayer;
|
||||
class plDynamicTextLayer;
|
||||
class plPassMtlBase;
|
||||
class plClothingItem;
|
||||
class plClothingMtl;
|
||||
class hsBitVector;
|
||||
|
||||
class plExportMaterialData
|
||||
{
|
||||
public:
|
||||
UInt32 fNumBlendChannels;
|
||||
hsGMaterial *fMaterial;
|
||||
};
|
||||
|
||||
class hsMaterialConverter
|
||||
{
|
||||
private:
|
||||
hsMaterialConverter();
|
||||
|
||||
public:
|
||||
~hsMaterialConverter();
|
||||
static hsMaterialConverter& Instance();
|
||||
|
||||
void Init(hsBool save, plErrorMsg *msg);
|
||||
|
||||
void FreeMaterialCache(const char* path);
|
||||
|
||||
static void GetUsedMaterials(plMaxNode* node, hsBitVector& used);
|
||||
static hsBool IsTwoSided(Mtl* m, int iFace);
|
||||
static hsBool PreserveUVOffset(Mtl* m);
|
||||
static hsBool IsMultiMat(Mtl *m);
|
||||
static hsBool IsMultipassMat(Mtl *m);
|
||||
static hsBool IsHsMaxMat(Mtl *m);
|
||||
static hsBool IsDecalMat(Mtl *m);
|
||||
static hsBool IsCompositeMat(Mtl *m);
|
||||
static hsBool IsParticleMat(Mtl *m);
|
||||
static hsBool IsHsEnvironMapMat(Mtl *m);
|
||||
static hsBool IsClothingMat(Mtl *m);
|
||||
// static hsBool IsPortalMat(Mtl *m);
|
||||
static hsBool HasAnimatedTextures(Texmap* texMap);
|
||||
static hsBool HasAnimatedMaterial(plMaxNode* node);
|
||||
static hsBool IsAnimatedMaterial(Mtl* mtl);
|
||||
static hsBool HasMaterialDiffuseOrOpacityAnimation(plMaxNode* node, Mtl* mtl=nil);
|
||||
static hsBool HasEmissiveLayer(plMaxNode* node, Mtl* mtl=nil);
|
||||
static hsBool IsWaterLayer(plMaxNode* node, Texmap* texMap);
|
||||
static hsBool IsFireLayer(plMaxNode* node, Texmap* texMap);
|
||||
static hsBool IsAVILayer(Texmap* texMap);
|
||||
static hsBool IsQTLayer(Texmap* texMap);
|
||||
static hsBool IsBinkLayer(Texmap* texMap);
|
||||
// static hsBool IsEnvironMapped(plMaxNode *node);
|
||||
// static hsBool IsPortal(plMaxNode* node);
|
||||
static hsBool ForceNoUvsFlatten(plMaxNode* node);
|
||||
// static hsBool IsRenderProc(Mtl* mtl);
|
||||
static Mtl* GetBaseMtl(Mtl* mtl);
|
||||
static Mtl* GetBaseMtl(plMaxNode* node);
|
||||
static int GetCoordMapping(StdUVGen *uvgen);
|
||||
static void GetNodesByMaterial(Mtl *mtl, hsTArray<plMaxNode*> &out);
|
||||
|
||||
static UInt32 VertexChannelsRequestMask(plMaxNode* node, int iSubMtl, Mtl* mtl);
|
||||
static UInt32 VertexChannelsRequiredMask(plMaxNode* node, int iSubMtl);
|
||||
static int NumVertexOpacityChannelsRequired(plMaxNode* node, int iSubMtl);
|
||||
static UInt32 ColorChannelsUseMask(plMaxNode* node, int iSubMtl);
|
||||
static int MaxUsedUVWSrc(plMaxNode* node, Mtl* mtl);
|
||||
|
||||
|
||||
static hsBool IsBumpLayer(Texmap* texMap);
|
||||
static hsBool IsBumpMtl(Mtl* mtl);
|
||||
static hsBool HasBumpLayer(plMaxNode* node, Mtl* mtl);
|
||||
static BitmapTex* GetBumpLayer(plMaxNode* node, Mtl* mtl);
|
||||
|
||||
static hsBool HasVisDists(plMaxNode* node, Mtl* subMtl, hsScalar& minDist, hsScalar& maxDist);
|
||||
static hsBool HasVisDists(plMaxNode* node, int iSubMtl, hsScalar& minDist, hsScalar& maxDist);
|
||||
|
||||
static hsBool IMustBeUniqueMaterial( Mtl *mtl );
|
||||
static hsBool IMustBeUniqueLayer( Texmap *layer );
|
||||
|
||||
static Mtl* FindSubMtlByName(TSTR& name, Animatable* anim);
|
||||
Mtl* FindSceneMtlByName(TSTR& name);
|
||||
|
||||
hsTArray<plExportMaterialData> *CreateMaterialArray(Mtl *maxMaterial, plMaxNode *node, UInt32 multiIndex);
|
||||
|
||||
// true if last material creation changed MAX time, invalidating current mesh
|
||||
hsBool ChangedTimes() { return fChangedTimes; }
|
||||
|
||||
Texmap *GetUVChannelBase(plMaxNode *node, Mtl* mtl, int which);
|
||||
|
||||
hsBool ClearDoneMaterials(plMaxNode* node);
|
||||
|
||||
int GetMaterialArray(Mtl *mtl, plMaxNode* node, hsTArray<hsGMaterial*>& out, UInt32 multiIndex = 0 );
|
||||
int GetMaterialArray(Mtl *mtl, hsTArray<hsGMaterial*>& out, UInt32 multiIndex = 0);
|
||||
void CollectConvertedMaterials(Mtl *mtl, hsTArray<hsGMaterial *> &out);
|
||||
|
||||
plClothingItem *GenerateClothingItem(plClothingMtl *mtl, const plLocation &loc);
|
||||
hsGMaterial* AlphaHackVersion(plMaxNode* node, Mtl* mtl, int subIndex); // used by DynamicDecals
|
||||
hsGMaterial* NonAlphaHackVersion(plMaxNode* node, Mtl* mtl, int subIndex);
|
||||
hsGMaterial* AlphaHackPrint(plMaxNode* node, Texmap* baseTex, UInt32 blendFlags);
|
||||
hsGMaterial* NonAlphaHackPrint(plMaxNode* node, Texmap* baseTex, UInt32 blendFlags);
|
||||
|
||||
plMipmap* GetStaticColorTexture(Color c, plLocation &loc); // Creates a 4x4 texture of the specified solid color;
|
||||
|
||||
enum {
|
||||
kColorRedBlack = 0x1,
|
||||
kColorRedGrey = 0x2,
|
||||
kColorRedWhite = 0x4,
|
||||
kColorRed = kColorRedBlack | kColorRedGrey | kColorRedWhite,
|
||||
|
||||
kColorGreenBlack = 0x8,
|
||||
kColorGreenGrey = 0x10,
|
||||
kColorGreenWhite = 0x20,
|
||||
kColorGreen = kColorGreenBlack | kColorGreenGrey | kColorGreenWhite,
|
||||
|
||||
kColorBlueBlack = 0x40,
|
||||
kColorBlueGrey = 0x80,
|
||||
kColorBlueWhite = 0x100,
|
||||
kColorBlue = kColorBlueBlack | kColorBlueGrey | kColorBlueWhite,
|
||||
|
||||
kColor = kColorRed | kColorGreen | kColorBlue,
|
||||
|
||||
kIllumRedBlack = 0x200,
|
||||
kIllumRedGrey = 0x400,
|
||||
kIllumRedWhite = 0x800,
|
||||
kIllumRed = kIllumRedBlack | kIllumRedGrey | kIllumRedWhite,
|
||||
|
||||
kIllumGreenBlack = 0x1000,
|
||||
kIllumGreenGrey = 0x2000,
|
||||
kIllumGreenWhite = 0x4000,
|
||||
kIllumGreen = kIllumGreenBlack | kIllumGreenGrey | kIllumGreenWhite,
|
||||
|
||||
kIllumBlueBlack = 0x8000,
|
||||
kIllumBlueGrey = 0x10000,
|
||||
kIllumBlueWhite = 0x20000,
|
||||
kIllumBlue = kIllumBlueBlack | kIllumBlueGrey | kIllumBlueWhite,
|
||||
|
||||
kIllum = kIllumRed | kIllumGreen | kIllumBlue,
|
||||
|
||||
kAlphaBlack = 0x40000,
|
||||
kAlphaGrey = 0x80000,
|
||||
kAlphaWhite = 0x100000,
|
||||
kAlpha = kAlphaBlack | kAlphaGrey | kAlphaWhite,
|
||||
|
||||
kAllChannels = kColor | kIllum | kAlpha // Adjust if more channels added.
|
||||
};
|
||||
|
||||
// All this to catch duplicate mats with same name. Sigh.
|
||||
struct DoneMaterialData
|
||||
{
|
||||
DoneMaterialData() : fHsMaterial(nil), fMaxMaterial(nil), fNode(nil),
|
||||
fSubMultiMat(false), fOwnedCopy(false) { }
|
||||
|
||||
hsGMaterial *fHsMaterial;
|
||||
Mtl *fMaxMaterial;
|
||||
plMaxNode *fNode;
|
||||
hsBool fSubMultiMat;
|
||||
hsBool fOwnedCopy;
|
||||
hsBool fRuntimeLit;
|
||||
UInt32 fSubMtlFlags;
|
||||
int fNumUVChannels;
|
||||
hsBool fMakeAlphaLayer;
|
||||
};
|
||||
|
||||
private:
|
||||
enum {
|
||||
kWarnedNoMoreDub = 0x1,
|
||||
kWarnedNoMoreMult = 0x2,
|
||||
kWarnedNoMoreBitmapLoadErr = 0x4,
|
||||
kWarnedSubMulti = 0x8,
|
||||
kWarnedCompMtlBadBlend = 0x10,
|
||||
kWarnedNoLayers = 0x20,
|
||||
kWarnedTooManyUVs = 0x40,
|
||||
kWarnedAlphaAddCombo = 0x80,
|
||||
kWarnedNoBaseTexture = 0x100,
|
||||
kWarnedNoUpperTexture = 0x200,
|
||||
kWarnedUpperTextureMissing = 0x400,
|
||||
kWarnedMissingClothingTexture = 0x800,
|
||||
kWarnedBadAnimSDLVarName = 0x1000,
|
||||
};
|
||||
|
||||
DoneMaterialData* IFindDoneMaterial(DoneMaterialData& done);
|
||||
hsBool IClearDoneMaterial(Mtl* mtl, plMaxNode* node);
|
||||
|
||||
hsGMaterial *IAddDefaultMaterial(plMaxNode *node);
|
||||
plMipmap *IGetUVTransTexture(plMaxNode *node, hsBool useU = true);
|
||||
void IInsertSingleBlendLayer(plMipmap *texture, hsGMaterial *mat, plMaxNode *node,
|
||||
int layerIdx, int UVChan);
|
||||
|
||||
hsGMaterial *ICreateMaterial(Mtl *mtl, plMaxNode *node, const char *name, int subIndex, int numUVChannels, hsBool makeAlphaLayer);
|
||||
hsGMaterial *IProcessMaterial(Mtl *mtl, plMaxNode *node, const char *name, int UVChan, int subMtlFlags = 0);
|
||||
|
||||
// ... calls one of:
|
||||
hsGMaterial *IProcessMultipassMtl(Mtl *mtl, plMaxNode *node, const char *name, int UVChan);
|
||||
hsGMaterial *IProcessCompositeMtl(Mtl *mtl, plMaxNode *node, const char *name, int UVChan, int subMtlFlags);
|
||||
hsGMaterial *IProcessParticleMtl(Mtl *mtl, plMaxNode *node, const char *name);
|
||||
hsBool IProcessPlasmaMaterial(Mtl *mtl, plMaxNode *node, hsGMaterial *mat, const char* namePrefix);
|
||||
|
||||
hsGMaterial* IInsertDoneMaterial(Mtl *mtl, hsGMaterial *hMat, plMaxNode *node, hsBool isMultiMat,
|
||||
hsBool forceCopy, hsBool runtimeLit, UInt32 subMtlFlags, int numUVChannels, hsBool makeAlphaLayer);
|
||||
|
||||
void IInsertBumpLayers(plMaxNode* node, hsGMaterial* mat, int bumpLayerIdx);
|
||||
void IInsertBumpLayers(plMaxNode* node, hsGMaterial* mat);
|
||||
plLayer* IMakeBumpLayer(plMaxNode* node, const char* nameBase, hsGMaterial* mat, UInt32 miscFlag);
|
||||
plMipmap* IGetBumpLutTexture(plMaxNode* node);
|
||||
|
||||
hsBool IHasSubMtl(Mtl* base, Mtl* sub);
|
||||
int IFindSubIndex(plMaxNode* node, Mtl* mtl);
|
||||
|
||||
// NOTE: each insert function potentially modifies the layers,
|
||||
// so make sure you own the material copy before calling these
|
||||
void IInsertAlphaBlendingLayers(Mtl *mtl, plMaxNode *node, hsGMaterial *mat, int UVChan,
|
||||
hsBool makeAlphaLayer);
|
||||
void IInsertMultipassBlendingLayers(Mtl *mtl, plMaxNode *node, hsGMaterial *mat, int UVChan,
|
||||
hsBool makeAlphaLayer);
|
||||
void IInsertCompBlendingLayers(Mtl *mtl, plMaxNode *node, hsGMaterial *mat, int subMtlFlags,
|
||||
int UVChan, hsBool makeAlphaLayer);
|
||||
|
||||
|
||||
void IAddLayerToMaterial(hsGMaterial *mat, plLayerInterface *layer);
|
||||
#if 0 // Out for now...
|
||||
void IInitAttrSurface(hsGLayer *hLay, StdMat *stdMtl, plMaxNode *node);
|
||||
void IInitAttrTexture(plMaxNode *node, Mtl *mtl, hsGLayer* hLay, Texmap *texMap, char *nodeName);
|
||||
void IInitAttrLayer(hsGLayer* hLay, Mtl *mtl, Texmap* layer, plMaxNode* node);
|
||||
#endif
|
||||
// ... and so forth
|
||||
hsBool IUVGenHasDynamicScale(plMaxNode* node, StdUVGen *uvGen);
|
||||
void IScaleLayerOpacity(plLayer* hLay, hsScalar scale);
|
||||
|
||||
hsGMaterial *ICheckForProjectedTexture(plMaxNode *node);
|
||||
hsGMaterial *IWrapTextureInMaterial(Texmap *texMap, plMaxNode *node);
|
||||
|
||||
BMM_Color_64 ICubeSample(Bitmap *bitmap[6], double phi, double theta);
|
||||
void IBuildSphereMap(Bitmap *bitmap[6], Bitmap *bm);
|
||||
#if 0 // DEFER_ANIM_MAT
|
||||
void IProcessAnimMaterial(BitmapTex *bitmapTex, hsGAnimLayer* at, UInt32 texFlags, UInt32 procFlags);
|
||||
#endif // DEFER_ANIM_MAT
|
||||
static hsBool ITextureTransformIsAnimated(Texmap *texmap);
|
||||
static hsBool IHasAnimatedControllers(Animatable* anim);
|
||||
static hsBool IIsAnimatedTexmap(Texmap* texmap);
|
||||
|
||||
static UInt32 ICheckPoints(const Point3& p0, const Point3& p1, const Point3& p2, const Point3& p3,
|
||||
int chan,
|
||||
UInt32 mBlack, UInt32 mGrey, UInt32 mWhite);
|
||||
static UInt32 ICheckPoints(const Point3& p0, const Point3& p1, const Point3& p2,
|
||||
int chan,
|
||||
UInt32 mBlack, UInt32 mGrey, UInt32 mWhite);
|
||||
|
||||
void IAppendWetLayer(plMaxNode* node, hsGMaterial* mat);
|
||||
static plBitmap* IGetFunkyRamp(plMaxNode* node, UInt32 funkyType);
|
||||
static void IAppendFunkyLayer(plMaxNode* node, Texmap* texMap, hsGMaterial* mat);
|
||||
static hsBool IHasFunkyOpacity(plMaxNode* node, Texmap* texMap);
|
||||
static UInt32 IGetFunkyType(Texmap* texMap);
|
||||
static UInt32 IGetOpacityRanges(plMaxNode* node, Texmap* texMap, hsScalar& tr0, hsScalar& op0, hsScalar& op1, hsScalar& tr1);
|
||||
|
||||
Interface *fInterface;
|
||||
hsConverterUtils& fConverterUtils;
|
||||
hsBool fSave;
|
||||
plErrorMsg *fErrorMsg;
|
||||
|
||||
Int32 fSubIndex;
|
||||
hsBool fChangedTimes;
|
||||
|
||||
char *fNodeName;
|
||||
UInt32 fWarned;
|
||||
|
||||
|
||||
DoneMaterialData fLastMaterial;
|
||||
hsTArray<DoneMaterialData> fDoneMaterials;
|
||||
|
||||
hsBool IsMatchingDoneMaterial(DoneMaterialData *dmd,
|
||||
Mtl *mtl, hsBool isMultiMat, UInt32 subMtlFlags, hsBool forceCopy, hsBool runtimeLit,
|
||||
plMaxNode *node, int numUVChannels, hsBool makeAlphaLayer);
|
||||
|
||||
void ISortDoneMaterials(hsTArray<DoneMaterialData*>& doneMats);
|
||||
hsBool IEquivalent(DoneMaterialData* one, DoneMaterialData* two);
|
||||
void IPrintDoneMat(hsStream* stream, const char* prefix, DoneMaterialData* doneMat);
|
||||
void IPrintDoneMaterials(const char* path, hsTArray<DoneMaterialData*>& doneMats);
|
||||
void IGenMaterialReport(const char* path);
|
||||
|
||||
public:
|
||||
// Apologies all around, but I need this list for dumping some export warnings. mf
|
||||
const hsTArray<struct DoneMaterialData>& DoneMaterials() { return fDoneMaterials; }
|
||||
|
||||
//hsBool CheckValidityOfSDLVarAnim(plPassMtlBase *mtl, char *varName, plMaxNode *node);
|
||||
};
|
||||
|
||||
extern hsMaterialConverter gMaterialConverter;
|
||||
|
||||
#endif
|
204
Sources/Tools/MaxConvert/hsMaxLayerBase.h
Normal file
204
Sources/Tools/MaxConvert/hsMaxLayerBase.h
Normal file
@ -0,0 +1,204 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
#ifndef __HSMAXLAYERBASE_H
|
||||
#define __HSMAXLAYERBASE_H
|
||||
|
||||
#include "stdmat.h"
|
||||
|
||||
#define HSMAX_LAYER_CLASS_ID 0x41990fe7
|
||||
|
||||
const Class_ID hsMaxLayerClassID(HSMAX_LAYER_CLASS_ID, 0x72404998);
|
||||
const Class_ID hsMaxMtlClassID(0x2f335902, 0x111d2ea7);
|
||||
const Class_ID hsEnvironMapMtlClassID(0x98777b3, 0x5eb270dd);
|
||||
|
||||
class hsMaxLayerBase : public BitmapTex {
|
||||
public:
|
||||
enum hsMatBlendFlags {
|
||||
kBlendTest = 0x1, // dev
|
||||
// Rest of blends are mutually exclusive
|
||||
kBlendAlpha = 0x2, // dev
|
||||
kBlendMult = 0x4, // dev
|
||||
kBlendAdd = 0x8, // dev
|
||||
kBlendAddColorTimesAlpha = 0x10, // dev
|
||||
kBlendAntiAlias = 0x20,
|
||||
kBlendDetail = 0x40,
|
||||
kBlendDetailAdd = 0x80,
|
||||
kBlendMask = kBlendAlpha
|
||||
| kBlendMult
|
||||
| kBlendAdd
|
||||
| kBlendAddColorTimesAlpha
|
||||
| kBlendAntiAlias
|
||||
| kBlendDetail
|
||||
| kBlendDetailAdd,
|
||||
kBlendInvertAlpha = 0x1000, // dev
|
||||
kBlendInvertColor = 0x2000, // dev
|
||||
kBlendAlphaMult = 0x4000,
|
||||
kBlendAlphaAdd = 0x8000,
|
||||
kBlendNoColor = 0x10000,
|
||||
kBlendNoVtxAlpha = 0x20000
|
||||
};
|
||||
|
||||
enum hsMatZFlags {
|
||||
kZIncLayer = 0x1, // dev
|
||||
kZOnlyZ = 0x2, // dev
|
||||
kZClearZ = 0x4, // dev
|
||||
kZNoZRead = 0x8, // dev
|
||||
kZNoZWrite = 0x10,
|
||||
kZMask = kZNoZWrite | kZClearZ | kZNoZRead,
|
||||
kZLODBias = 0x20
|
||||
};
|
||||
|
||||
enum hsMatShadeFlags {
|
||||
kShadeSoftShadow = 0x1, // view, dev
|
||||
kShadeNoProjectors = 0x2, // projector
|
||||
kShadeVertexShade = 0x20, // dev
|
||||
kShadeNoShade = 0x40, // view,dev
|
||||
kShadeBlack = kShadeNoShade,
|
||||
kShadeSpecular = 0x80, // view, dev
|
||||
kShadeNoFog = 0x100, // dev
|
||||
kShadeWhite = 0x200,
|
||||
kShadeSpecularAlpha = 0x400,
|
||||
kShadeSpecularColor = 0x800,
|
||||
kShadeSpecularHighlight = 0x1000,
|
||||
kShadeVertColShade = 0x2000,
|
||||
kShadeInherit = 0x4000
|
||||
};
|
||||
|
||||
enum hsMatMiscFlags {
|
||||
kMiscWireFrame = 0x1, // dev (running out of bits)
|
||||
kMiscDrawMeshOutlines = 0x2, // dev, currently unimplemented
|
||||
kMiscTwoSided = 0x4, // view,dev
|
||||
kMiscDrawAsSplats = 0x8, // dev? bwt
|
||||
kMiscMipMap = 0x10,
|
||||
kMiscUseBitmap = 0x20,
|
||||
kMiscIntensityOnly = 0x40,
|
||||
kMiscAutoStart = 0x80,
|
||||
kMiscDetailBias = 0x100, // obsolete...
|
||||
kMiscDetailMax = 0x200, // obsolete...
|
||||
kMiscExplicitMipmap = 0x400,
|
||||
kMiscAdjustPlane = 0x800,
|
||||
kMiscAdjustCylinder = 0x1000,
|
||||
kMiscAdjustSphere = 0x2000,
|
||||
kMiscTroubledLoner = 0x4000,
|
||||
kMiscBindSkip = 0x8000,
|
||||
kMiscBindMask = 0x10000,
|
||||
kMiscForceNonCompressed = 0x20000,
|
||||
kMiscNoMaxSize = 0x40000,
|
||||
kMiscHalfSize = 0x80000,
|
||||
kMiscBindNext = 0x100000,
|
||||
kMiscBindPrev = 0x200000,
|
||||
kMiscReserved = 0x400000
|
||||
};
|
||||
|
||||
enum ProcType {
|
||||
kProcTypeDefault,
|
||||
kProcTypeWater
|
||||
};
|
||||
|
||||
enum hsMatUsage {
|
||||
kUseNone = 0x0,
|
||||
kUseBase = 0x1,
|
||||
kUseDetail = 0x2,
|
||||
kUseGrime = 0x4,
|
||||
kUseTransition = 0x8,
|
||||
kUseHighlight = 0x10,
|
||||
kUseMask = 0x20,
|
||||
kUseShadowLight = 0x40,
|
||||
kUseHelper = 0x80,
|
||||
|
||||
kUseGuess = 0x10000000
|
||||
};
|
||||
|
||||
public:
|
||||
// For hsMaxMtl... Special case for higher layers. Sigh.
|
||||
virtual void SetDirty(BOOL state) = 0;
|
||||
virtual void SetBlendFlag(int i, BOOL state) = 0;
|
||||
virtual void SetZFlag(int flag, BOOL state) = 0;
|
||||
virtual void SetShadeFlag(int flag, BOOL state) = 0;
|
||||
virtual void SetMiscFlag(int flag, BOOL state) = 0;
|
||||
virtual void SetProcType(ProcType type) = 0;
|
||||
virtual void SetUsage(hsMatUsage use) = 0;
|
||||
virtual void GuessUsage() = 0;
|
||||
|
||||
// For interactive renderer
|
||||
virtual Color GetAmbient(int mtlNum=0, BOOL backFace=FALSE) = 0;
|
||||
virtual Color GetColor(int mtlNum=0, BOOL backFace=FALSE) = 0;
|
||||
|
||||
virtual float GetShininess(int mtlNum=0, BOOL backFace=FALSE) = 0;
|
||||
virtual float GetShinStr(int mtlNum=0, BOOL backFace=FALSE) = 0;
|
||||
virtual float GetOpacity(int mtlNum=0, BOOL backFace=FALSE) = 0;
|
||||
|
||||
// For exporter
|
||||
virtual Color GetAmbient(TimeValue t) const = 0;
|
||||
virtual Color GetColor(TimeValue t) const = 0;
|
||||
|
||||
virtual float GetShininess(TimeValue t) const = 0;
|
||||
virtual float GetShinStr(TimeValue t) const = 0;
|
||||
virtual float GetMapPercent(TimeValue t) const = 0;
|
||||
virtual float GetOpacity(TimeValue t) const = 0;
|
||||
virtual float GetMipMapBlur(TimeValue t) const = 0;
|
||||
virtual float GetLODBias(TimeValue t) const = 0;
|
||||
virtual float GetDetailDropoffStart(TimeValue t) const = 0;
|
||||
virtual float GetDetailDropoffStop(TimeValue t) const = 0;
|
||||
virtual float GetDetailMax(TimeValue t) const = 0;
|
||||
virtual float GetDetailMin(TimeValue t) const = 0;
|
||||
virtual int GetEnvironMapSize(TimeValue t) const = 0;
|
||||
|
||||
virtual BOOL GetDirty() const = 0;
|
||||
virtual ULONG GetBlendFlags() const = 0;
|
||||
virtual ULONG GetZFlags() const = 0;
|
||||
virtual ULONG GetShadeFlags() const = 0;
|
||||
virtual ULONG GetMiscFlags() const = 0;
|
||||
virtual ProcType GetProcType() const = 0;
|
||||
virtual hsMatUsage GetUsage() const = 0;
|
||||
|
||||
virtual int GetNumExplicitMipmaps() const = 0;
|
||||
virtual TCHAR *GetExplicitMipmapName(int i) const = 0;
|
||||
virtual BOOL ExplicitMipmapEnabled(int i) const = 0;
|
||||
virtual int GetExplicitMipmapLevel(int i) const = 0;
|
||||
|
||||
// KLUDGE - Had to do this to compile under MAX4 beta
|
||||
virtual void fnReload() {};
|
||||
virtual void fnViewImage() {};
|
||||
};
|
||||
|
||||
#endif
|
457
Sources/Tools/MaxConvert/hsVertexShader.cpp
Normal file
457
Sources/Tools/MaxConvert/hsVertexShader.cpp
Normal file
@ -0,0 +1,457 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// hsVertexShader Class Functions //
|
||||
// //
|
||||
//// Version History /////////////////////////////////////////////////////////
|
||||
// //
|
||||
// 5.9.2001 mcn - Updated to reflect the new (temporary) vertex color/ //
|
||||
// lighting model. //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include "HeadSpin.h"
|
||||
|
||||
#include "Max.h"
|
||||
#include "stdmat.h"
|
||||
#include "istdplug.h"
|
||||
#include "dummy.h"
|
||||
#include "notetrck.h"
|
||||
|
||||
#include "../MaxMain/plMaxNode.h"
|
||||
#include "hsBitVector.h"
|
||||
|
||||
#include "hsMatrix44.h"
|
||||
#include "hsTemplates.h"
|
||||
#include "../plSurface/hsGMaterial.h"
|
||||
|
||||
#include "UserPropMgr.h"
|
||||
#include "hsMaxLayerBase.h"
|
||||
#include "hsVertexShader.h"
|
||||
|
||||
#include "hsConverterUtils.h"
|
||||
#include "hsControlConverter.h"
|
||||
#include "hsExceptionStack.h"
|
||||
#include "../plSurface/hsGMaterial.h"
|
||||
#include "../plSurface/plLayerInterface.h"
|
||||
|
||||
#include "../plDrawable/plGeometrySpan.h"
|
||||
|
||||
#include "plMaxLightContext.h"
|
||||
#include "plRenderGlobalContext.h"
|
||||
#include "plLightMapGen.h"
|
||||
|
||||
#define MF_NATIVE_MAX_LIGHT
|
||||
#define MF_NO_RAY_SHADOW
|
||||
|
||||
extern UserPropMgr gUserPropMgr;
|
||||
extern TimeValue GetTime(Interface *gi);
|
||||
|
||||
//===========================================================================
|
||||
// hsVertexShader
|
||||
//===========================================================================
|
||||
|
||||
hsVertexShader::hsVertexShader() :
|
||||
fConverterUtils(hsConverterUtils::Instance()),
|
||||
fInterface(nil),
|
||||
fLightMapGen(nil),
|
||||
fShaded(0)
|
||||
{
|
||||
hsGuardBegin("hsVertexShader::hsVertexShader");
|
||||
fLocalToWorld.Reset();
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
hsVertexShader::~hsVertexShader()
|
||||
{
|
||||
hsGuardBegin("hsVertexShader::~hsVertexShader");
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
hsVertexShader& hsVertexShader::Instance()
|
||||
{
|
||||
hsGuardBegin("hsVertexShader::Instance");
|
||||
static hsVertexShader instance;
|
||||
return instance;
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
void hsVertexShader::Open()
|
||||
{
|
||||
hsGuardBegin("hsVertexShader::InitLights");
|
||||
|
||||
fLocalToWorld.Reset();
|
||||
|
||||
fInterface = ::GetCOREInterface();
|
||||
|
||||
fLightMapGen = &plLightMapGen::Instance();
|
||||
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
void hsVertexShader::Close()
|
||||
{
|
||||
hsGuardBegin("hsVertexShader::DeInitLights");
|
||||
|
||||
fLightMapGen = nil;
|
||||
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
//// ShadeNode ///////////////////////////////////////////////////////////////
|
||||
// Same as the other ShadeNode, only this shades an array of plGeometrySpans.
|
||||
|
||||
void hsVertexShader::ShadeNode(INode* node, hsMatrix44& l2w, hsMatrix44& w2l, hsTArray<plGeometrySpan *> &spans)
|
||||
{
|
||||
// If we're flagged for WaterColor, our vertex colors are already done.
|
||||
if( ((plMaxNodeBase*)node)->GetCalcEdgeLens() || node->UserPropExists("XXXWaterColor") )
|
||||
return;
|
||||
|
||||
fLightMapGen->InitNode(node);
|
||||
|
||||
fLocalToWorld = l2w;
|
||||
hsMatrix44 tempMatrix = w2l; // l2w's inverse
|
||||
tempMatrix.GetTranspose( &fNormalToWorld ); // Inverse-transpose of the fLocalToWorld matrix,
|
||||
|
||||
int i;
|
||||
for( i = 0; i < spans.GetCount(); i++ )
|
||||
IShadeSpan( spans[ i ], node);
|
||||
|
||||
fLightMapGen->DeInitNode();
|
||||
|
||||
fShaded++;
|
||||
}
|
||||
|
||||
//// IShadeSpan //////////////////////////////////////////////////////////////
|
||||
// Shades a single plGeometrySpan.
|
||||
// 5.9.2001 mcn - Updated to support the new (temporary) vertex color/lighting
|
||||
// method.
|
||||
|
||||
void hsVertexShader::IShadeSpan( plGeometrySpan *span, INode* node )
|
||||
{
|
||||
hsColorRGBA preDiffuse, rtDiffuse, matAmbient;
|
||||
hsBitVector dirtyVector;
|
||||
int i;
|
||||
hsBool translucent, shadeIt, addingIt;
|
||||
plLayerInterface *layer = nil;
|
||||
|
||||
|
||||
hsGuardBegin("hsVertexShader::ShadeSpan");
|
||||
|
||||
const char* dbgNodeName = node->GetName();
|
||||
|
||||
if( span->fNumVerts == 0 )
|
||||
return;
|
||||
|
||||
fShadeColorTable = TRACKED_NEW hsColorRGBA[ span->fNumVerts ];
|
||||
fIllumColorTable = TRACKED_NEW hsColorRGBA[ span->fNumVerts ];
|
||||
|
||||
translucent = IsTranslucent( span->fMaterial );
|
||||
|
||||
/// Get material layer #0
|
||||
addingIt = false;
|
||||
shadeIt = !( span->fProps & plGeometrySpan::kPropNoPreShade );
|
||||
|
||||
if( span->fMaterial->GetNumLayers() != 0 )
|
||||
{
|
||||
layer = span->fMaterial->GetLayer( 0 );
|
||||
if( layer->GetShadeFlags() & hsGMatState::kShadeNoShade )
|
||||
shadeIt = false;
|
||||
if( layer->GetBlendFlags() & hsGMatState::kBlendAdd )
|
||||
addingIt = true;
|
||||
}
|
||||
float opacity = 1.f;
|
||||
for( i = 0; i < span->fMaterial->GetNumLayers(); i++ )
|
||||
{
|
||||
plLayerInterface* lay = span->fMaterial->GetLayer(i);
|
||||
if( (lay->GetBlendFlags() & hsGMatState::kBlendAlpha)
|
||||
&&
|
||||
(
|
||||
!i
|
||||
||
|
||||
(lay->GetMiscFlags() & hsGMatState::kMiscRestartPassHere)
|
||||
)
|
||||
)
|
||||
{
|
||||
opacity = span->fMaterial->GetLayer(i)->GetOpacity();
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate color table
|
||||
if( shadeIt )
|
||||
IShadeVertices( span, &dirtyVector, node, translucent );
|
||||
else
|
||||
{
|
||||
for( i = 0; i < span->fNumVerts; i++ )
|
||||
{
|
||||
/// This is good for the old way, but not sure about the new way. Test once new way is in again -mcn
|
||||
// fShadeColorTable[ i ].Set( 1, 1, 1, 1 );
|
||||
// fIllumColorTable[ i ].Set( 0, 0, 0, 1 );
|
||||
hsPoint3 position;
|
||||
hsVector3 normal;
|
||||
hsColorRGBA color, illum;
|
||||
|
||||
span->ExtractVertex( i, &position, &normal, &color, &illum );
|
||||
span->ExtractInitColor( i, &color, &illum );
|
||||
fShadeColorTable[ i ].Set( color.r, color.g, color.b, color.a );
|
||||
fIllumColorTable[ i ].Set( illum.r, illum.g, illum.b, 1 );
|
||||
}
|
||||
}
|
||||
|
||||
/// Get mat colors to modulate by
|
||||
if( layer == nil )
|
||||
{
|
||||
preDiffuse.Set( 1, 1, 1, 1 );
|
||||
rtDiffuse.Set( 1, 1, 1, 1 );
|
||||
matAmbient.Set( 0, 0, 0, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( layer->GetShadeFlags() & hsGMatState::kShadeWhite )
|
||||
{
|
||||
preDiffuse.Set( 1, 1, 1, 1 );
|
||||
rtDiffuse.Set( 1, 1, 1, 1 );
|
||||
matAmbient.Set( 0, 0, 0, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
preDiffuse = layer->GetPreshadeColor(); // This is for vertex-based lighting, which basically ignores preshading
|
||||
rtDiffuse = layer->GetRuntimeColor(); // This is for vertex-based lighting, which basically ignores preshading
|
||||
matAmbient = layer->GetAmbientColor();
|
||||
matAmbient.a = 0;
|
||||
}
|
||||
preDiffuse.a = opacity;
|
||||
rtDiffuse.a = opacity;
|
||||
}
|
||||
#if 0
|
||||
|
||||
/// Multiply by the material color, and scale by opacity if we're additive blending
|
||||
/// Apply colors now, multiplying by the material color as we go
|
||||
for( i = 0; i < span->fNumVerts; i++ )
|
||||
{
|
||||
fShadeColorTable[ i ] *= matDiffuse;
|
||||
fShadeColorTable[ i ] += matAmbient;
|
||||
fIllumColorTable[ i ] *= matDiffuse;
|
||||
fIllumColorTable[ i ] += matAmbient;
|
||||
}
|
||||
|
||||
if( addingIt )
|
||||
{
|
||||
for( i = 0; i < span->fNumVerts; i++ )
|
||||
{
|
||||
float opacity = fShadeColorTable[ i ].a;
|
||||
fShadeColorTable[ i ] *= opacity;
|
||||
fIllumColorTable[ i ] *= opacity;
|
||||
}
|
||||
}
|
||||
#else
|
||||
/// Combine shade and illum together into the diffuse color
|
||||
if( ( span->fProps & plGeometrySpan::kLiteMask ) != plGeometrySpan::kLiteMaterial )
|
||||
{
|
||||
/// The two vertex lighting formulas take in a vetex color pre-processed, i.e. in
|
||||
/// the form of: vtxColor = ( maxVtxColor * materialDiffuse + maxIllumColor )
|
||||
span->fProps |= plGeometrySpan::kDiffuseFoldedIn;
|
||||
if( !shadeIt )
|
||||
{
|
||||
for( i = 0; i < span->fNumVerts; i++ )
|
||||
{
|
||||
fIllumColorTable[ i ].a = 0;
|
||||
fShadeColorTable[ i ] = (fShadeColorTable[ i ] * rtDiffuse) + fIllumColorTable[ i ];
|
||||
fIllumColorTable[ i ].Set( 0, 0, 0, 0 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i = 0; i < span->fNumVerts; i++ )
|
||||
{
|
||||
fIllumColorTable[ i ].a = 1.f;
|
||||
// Following needs to be changed to allow user input vertex colors to modulate
|
||||
// the runtime light values.
|
||||
// fShadeColorTable[ i ] = fIllumColorTable[ i ] * rtDiffuse;
|
||||
fShadeColorTable[ i ] = fShadeColorTable[ i ] * fIllumColorTable[ i ] * rtDiffuse;
|
||||
fIllumColorTable[ i ].Set( 0, 0, 0, 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !shadeIt )
|
||||
{
|
||||
// Not shaded, so runtime lit, so we want BLACK vertex colors
|
||||
for( i = 0; i < span->fNumVerts; i++ )
|
||||
{
|
||||
fShadeColorTable[ i ].Set( 0, 0, 0, 0 );
|
||||
fIllumColorTable[ i ].Set( 0, 0, 0, 0 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i = 0; i < span->fNumVerts; i++ )
|
||||
{
|
||||
fShadeColorTable[ i ] *= fIllumColorTable[ i ];
|
||||
fIllumColorTable[ i ].Set( 0, 0, 0, 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Loop and stuff
|
||||
for( i = 0; i < span->fNumVerts; i++ )
|
||||
span->StuffVertex( i, fShadeColorTable + i, fIllumColorTable + i );
|
||||
|
||||
delete [] fShadeColorTable;
|
||||
delete [] fIllumColorTable;
|
||||
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
//// IShadeVertices //////////////////////////////////////////////////////////
|
||||
// Shades an array of vertices from a plGeometrySpan.
|
||||
// 5.9.2001 mcn - Updated for the new lighting model. Now on runtime, we
|
||||
// want the following properties on each vertex:
|
||||
// diffuseColor = vertexColor * matDiffuse + matAmbient (including alpha)
|
||||
// specularColor = ( illumniation + pre-shading ) * matDiffuse + matAmbient
|
||||
// We do the mat modulation outside of this function, so we
|
||||
// just gotta make sure the two arrays get the right values.
|
||||
|
||||
void hsVertexShader::IShadeVertices( plGeometrySpan *span, hsBitVector *dirtyVector, INode* node, hsBool translucent )
|
||||
{
|
||||
hsGuardBegin( "hsVertexShader::IShadeVertices" );
|
||||
|
||||
plMaxNode* maxNode = (plMaxNode*)node;
|
||||
if( maxNode->CanConvert() && (nil != maxNode->GetLightMapComponent()) )
|
||||
return;
|
||||
|
||||
int index;
|
||||
|
||||
hsPoint3 position;
|
||||
hsVector3 normal;
|
||||
hsColorRGBA color, illum;
|
||||
plTmpVertex3 *vertices;
|
||||
|
||||
|
||||
/// Allocate temp vertex array
|
||||
vertices = TRACKED_NEW plTmpVertex3[ span->fNumVerts ];
|
||||
for( index = 0; index < span->fNumVerts; index++ )
|
||||
{
|
||||
span->ExtractVertex( index, &position, &normal, &color, &illum );
|
||||
span->ExtractInitColor( index, &color, &illum );
|
||||
|
||||
/// fShadeColorTable is the shaded portion. fIllumColorTable is the illuminated portion;
|
||||
/// for more and less confusing details, see above.
|
||||
fShadeColorTable[ index ].Set( color.r, color.g, color.b, color.a );
|
||||
fIllumColorTable[ index ].Set( illum.r, illum.g, illum.b, 1 );
|
||||
|
||||
position = fLocalToWorld * position;
|
||||
normal = fNormalToWorld * normal;
|
||||
|
||||
vertices[ index ].fLocalPos = position;
|
||||
vertices[ index ].fNormal = normal;
|
||||
vertices[ index ].fNormal.Normalize();
|
||||
}
|
||||
|
||||
const char* dbgNodeName = node->GetName();
|
||||
|
||||
TimeValue t = fInterface->GetTime();
|
||||
Box3 bbox;
|
||||
node->EvalWorldState(t).obj->GetDeformBBox(t, bbox, &node->GetObjectTM(t));
|
||||
plMaxLightContext ctx(bbox, t);
|
||||
|
||||
for( index = 0; index < span->fNumVerts; index++ )
|
||||
INativeShadeVtx(fIllumColorTable[index], ctx, vertices[ index ], translucent);
|
||||
|
||||
// Delete temp arrays
|
||||
delete [] vertices;
|
||||
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
void hsVertexShader::INativeShadeVtx(hsColorRGBA& shade, plMaxLightContext& ctx, const plTmpVertex3& vtx, hsBool translucent)
|
||||
{
|
||||
ctx.SetPoint(vtx.fLocalPos, vtx.fNormal);
|
||||
|
||||
Color color = fLightMapGen->ShadePoint(ctx);
|
||||
shade.r += color.r;
|
||||
shade.g += color.g;
|
||||
shade.b += color.b;
|
||||
|
||||
// To handle two-sided translucency here, we should compute the shade on each side and sum them.
|
||||
if( translucent )
|
||||
{
|
||||
ctx.SetPoint(vtx.fLocalPos, -vtx.fNormal);
|
||||
color = fLightMapGen->ShadePoint(ctx);
|
||||
shade.r += color.r;
|
||||
shade.g += color.g;
|
||||
shade.b += color.b;
|
||||
}
|
||||
}
|
||||
|
||||
void hsVertexShader::INativeShadowVtx(hsColorRGBA& shade, plMaxLightContext& ctx, const plTmpVertex3& vtx, hsBool translucent)
|
||||
{
|
||||
ctx.SetPoint(vtx.fLocalPos, vtx.fNormal);
|
||||
|
||||
Color color = fLightMapGen->ShadowPoint(ctx);
|
||||
shade.r += color.r;
|
||||
shade.g += color.g;
|
||||
shade.b += color.b;
|
||||
}
|
||||
|
||||
hsBool hsVertexShader::IsTranslucent( hsGMaterial *material )
|
||||
{
|
||||
hsGuardBegin("hsVertexShader::IsTranslucent");
|
||||
|
||||
if( material )
|
||||
{
|
||||
plLayerInterface* layer = material->GetLayer(0);
|
||||
if( layer && ( layer->GetShadeFlags() & hsGMatState::kShadeSoftShadow ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
|
101
Sources/Tools/MaxConvert/hsVertexShader.h
Normal file
101
Sources/Tools/MaxConvert/hsVertexShader.h
Normal file
@ -0,0 +1,101 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
#ifndef __HSVERTEXSHADER_H
|
||||
#define __HSVERTEXSHADER_H
|
||||
|
||||
class hsConverterUtils;
|
||||
class hsBitVector;
|
||||
|
||||
class plMaxLightContext;
|
||||
class plGeometrySpan;
|
||||
struct hsColorRGBA;
|
||||
class plLightMapGen;
|
||||
|
||||
class hsVertexShader
|
||||
{
|
||||
private:
|
||||
hsVertexShader();
|
||||
public:
|
||||
virtual ~hsVertexShader();
|
||||
|
||||
static hsVertexShader& Instance();
|
||||
|
||||
void ShadeNode(INode* node, hsMatrix44& l2w, hsMatrix44& w2l, hsTArray<plGeometrySpan *> &spans);
|
||||
|
||||
void Open();
|
||||
void Close();
|
||||
|
||||
private:
|
||||
|
||||
/// Temporary vertex class
|
||||
class plTmpVertex3
|
||||
{
|
||||
public:
|
||||
hsPoint3 fLocalPos;
|
||||
hsVector3 fNormal;
|
||||
};
|
||||
|
||||
hsBool ILightIncludesNode(LightObject* light, INode* node);
|
||||
|
||||
void INativeShadeVtx(hsColorRGBA& shade, plMaxLightContext& ctx, const plTmpVertex3& vtx, hsBool translucent);
|
||||
void INativeShadowVtx(hsColorRGBA& shade, plMaxLightContext& ctx, const plTmpVertex3& vtx, hsBool translucent);
|
||||
|
||||
hsBool IsTranslucent( hsGMaterial *material );
|
||||
|
||||
void IShadeSpan( plGeometrySpan *span, INode* node );
|
||||
void IShadeVertices( plGeometrySpan *span, hsBitVector *dirtyVector, INode* node, hsBool translucent );
|
||||
|
||||
private:
|
||||
Interface *fInterface;
|
||||
hsConverterUtils &fConverterUtils;
|
||||
|
||||
plLightMapGen* fLightMapGen;
|
||||
|
||||
hsMatrix44 fLocalToWorld, fNormalToWorld; // fN2W is inv-transpose of fL2W
|
||||
|
||||
int fShaded; // just record-keeping
|
||||
|
||||
hsColorRGBA *fShadeColorTable;
|
||||
hsColorRGBA *fIllumColorTable;
|
||||
};
|
||||
|
||||
#endif
|
700
Sources/Tools/MaxConvert/plBitmapCreator.cpp
Normal file
700
Sources/Tools/MaxConvert/plBitmapCreator.cpp
Normal file
@ -0,0 +1,700 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
#include "hsTypes.h"
|
||||
#include "max.h"
|
||||
#include <commdlg.h>
|
||||
#include "bmmlib.h"
|
||||
|
||||
#include "../../Plasma/PubUtilLib/plGImage/plMipmap.h"
|
||||
#include "hsExceptionStack.h"
|
||||
#include "../../Plasma/PubUtilLib/plGImage/hsCodecManager.h"
|
||||
|
||||
#include "plBitmapCreator.h"
|
||||
|
||||
#include "../MaxMain/plPluginResManager.h"
|
||||
#include "../MaxExport/plErrorMsg.h"
|
||||
#include "../MaxPlasmaMtls/Layers/plStaticEnvLayer.h"
|
||||
|
||||
#include "../plGImage/plMipmap.h"
|
||||
#include "../plGImage/plDynamicTextMap.h"
|
||||
#include "../plGImage/plCubicEnvironmap.h"
|
||||
#include "../pnKeyedObject/plKey.h"
|
||||
#include "../pnKeyedObject/plUoid.h"
|
||||
#include "../plResMgr/plRegistryHelpers.h"
|
||||
#include "../plResMgr/plLocalization.h"
|
||||
#include "../plAgeDescription/plAgeDescription.h"
|
||||
|
||||
//// plCommonBitmapLib ///////////////////////////////////////////////////////
|
||||
// Derived class for our textures, since they all go in a common page
|
||||
// (namely, "Textures")
|
||||
|
||||
#include "../MaxMain/plCommonObjLib.h"
|
||||
|
||||
class plCommonBitmapLib : public plCommonObjLib
|
||||
{
|
||||
public:
|
||||
virtual hsBool IsInteresting( const plKey &objectKey )
|
||||
{
|
||||
if( objectKey->GetUoid().GetClassType() == plCubicEnvironmap::Index() ||
|
||||
objectKey->GetUoid().GetClassType() == plMipmap::Index() )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
static plCommonBitmapLib sCommonBitmapLib;
|
||||
|
||||
|
||||
plBitmapCreator::plBitmapCreator()
|
||||
{
|
||||
fErrorMsg = nil;
|
||||
}
|
||||
plBitmapCreator::~plBitmapCreator()
|
||||
{
|
||||
}
|
||||
|
||||
plBitmapCreator &plBitmapCreator::Instance()
|
||||
{
|
||||
static plBitmapCreator fInstance;
|
||||
return fInstance;
|
||||
}
|
||||
|
||||
void plBitmapCreator::Init( hsBool save, plErrorMsg *msg )
|
||||
{
|
||||
fErrorMsg = msg;
|
||||
}
|
||||
|
||||
void plBitmapCreator::DeInit( void )
|
||||
{
|
||||
CleanUpMaps();
|
||||
}
|
||||
|
||||
void plBitmapCreator::CleanUpMaps( void )
|
||||
{
|
||||
sCommonBitmapLib.ClearObjectList();
|
||||
}
|
||||
|
||||
void plBitmapCreator::DeleteExportedBitmap( const plKey &constKey )
|
||||
{
|
||||
plKey key = constKey;
|
||||
sCommonBitmapLib.RemoveObjectAndKey( key );
|
||||
}
|
||||
|
||||
//
|
||||
// Create Bitmap
|
||||
//
|
||||
plMipmap *plBitmapCreator::ICreateBitmap(plBitmapData *bd)
|
||||
{
|
||||
hsGuardBegin("hsConverterUtils::CreateBitmap");
|
||||
|
||||
// Load the bitmap
|
||||
BitmapInfo bi;
|
||||
bi.SetName(bd->fileName);
|
||||
|
||||
#if 0 // This isn't really an issue since the textures are packed -Colin
|
||||
const int kMaxFileNameLength = 30;
|
||||
if (strlen(bi.Filename()) > kMaxFileNameLength)
|
||||
{
|
||||
// Allow to continue, But make it painful
|
||||
char errStr[256];
|
||||
sprintf(errStr, "File name longer than %d, won't burn to CD (%s)", kMaxFileNameLength, bi.Filename());//bitmapTex->GetName());
|
||||
MessageBox(GetActiveWindow(), errStr, bd->fileName, MB_OK|MB_ICONEXCLAMATION);
|
||||
}
|
||||
#endif
|
||||
|
||||
hsBool notMipped = (bd->texFlags & plMipmap::kForceOneMipLevel) != 0;
|
||||
float sigma = bd->sig;
|
||||
|
||||
// Load the bitmap
|
||||
Bitmap *bm = TheManager->Load(&bi);
|
||||
if (!bm)
|
||||
{
|
||||
// FIXME
|
||||
/*
|
||||
if (fErrorMsg->Set(!(fWarned & kWarnedNoMoreBitmapLoadErr),
|
||||
"Error loading bitmap", pathName).CheckAskOrCancel())
|
||||
{
|
||||
fWarned |= kWarnedNoMoreBitmapLoadErr;
|
||||
}
|
||||
*/
|
||||
return nil;
|
||||
}
|
||||
BitmapStorage *storage = bm->Storage();
|
||||
BitmapInfo *bInfo = &storage->bi;
|
||||
|
||||
ICheckOutBitmap(bInfo, bm, bd->fileName);
|
||||
|
||||
//
|
||||
// Create a plMipmap
|
||||
//
|
||||
plMipmap *hBitmap = TRACKED_NEW plMipmap;
|
||||
if( (bm->Width() ^ (bm->Width() & -bm->Width()))
|
||||
||(bm->Height() ^ (bm->Height() & -bm->Height())) )
|
||||
{
|
||||
IResampBitmap(bm, *hBitmap);
|
||||
}
|
||||
else if( ((bm->Width() >> 3) > bm->Height())||((bm->Height() >> 3) > bm->Width()) )
|
||||
{
|
||||
IResampBitmap(bm, *hBitmap);
|
||||
}
|
||||
else
|
||||
{
|
||||
ICopyBitmap(bm, *hBitmap);
|
||||
}
|
||||
bm->DeleteThis();
|
||||
|
||||
if( bd->invertAlpha )
|
||||
IInvertAlpha(*hBitmap);
|
||||
|
||||
// Do it
|
||||
plMipmap *hMipmap = nil;
|
||||
if (sigma > 0.f)
|
||||
{
|
||||
hMipmap = TRACKED_NEW plMipmap(hBitmap, sigma, bd->createFlags, bd->detailDropoffStart,
|
||||
bd->detailDropoffStop, bd->detailMax, bd->detailMin);
|
||||
}
|
||||
else
|
||||
{
|
||||
hMipmap = TRACKED_NEW plMipmap(hBitmap, -1.f, bd->createFlags, bd->detailDropoffStart,
|
||||
bd->detailDropoffStop, bd->detailMax, bd->detailMin);
|
||||
}
|
||||
delete hBitmap;
|
||||
|
||||
/// Clamp the border if we're using clamping
|
||||
if( bd->clampFlags != 0 )
|
||||
{
|
||||
hMipmap->EnsureKonstantBorder( ( bd->clampFlags & plBitmapData::kClampU ) ? true : false,
|
||||
( bd->clampFlags & plBitmapData::kClampV ) ? true : false );
|
||||
}
|
||||
|
||||
/// Cut this down to whatever size we were told to :)
|
||||
if( bd->maxDimension != 0 )
|
||||
hMipmap->ClipToMaxSize( bd->maxDimension );
|
||||
|
||||
if( notMipped )
|
||||
{
|
||||
// Done AFTER ClipToMaxSize() so we still get the export size specified
|
||||
hMipmap->RemoveMipping();
|
||||
}
|
||||
|
||||
hBitmap = hMipmap;
|
||||
|
||||
UInt32 flagsToSet = 0;
|
||||
|
||||
if( bd->texFlags & plMipmap::kNoMaxSize )
|
||||
flagsToSet |= plMipmap::kNoMaxSize;
|
||||
if( bd->texFlags & plMipmap::kHalfSize )
|
||||
flagsToSet |= plMipmap::kHalfSize;
|
||||
if( bd->texFlags & plMipmap::kDontThrowAwayImage )
|
||||
flagsToSet |= plMipmap::kDontThrowAwayImage;
|
||||
|
||||
hBitmap->SetFlags( hBitmap->GetFlags() | flagsToSet );
|
||||
if (bd->useJPEG)
|
||||
hBitmap->fCompressionType = plMipmap::kJPEGCompression;
|
||||
|
||||
// FIXME
|
||||
if (/*fSave &&*/ !(bd->texFlags & plMipmap::kForceNonCompressed) && !bd->useJPEG)
|
||||
{
|
||||
// Are we on? Check Plasma Util panel
|
||||
// SwitchUtil *pu = (SwitchUtil *)CreateInstance(UTILITY_CLASS_ID, PlasmaUtilClassID);
|
||||
// if (!pu || pu->TextureCompressionEnabled())
|
||||
{
|
||||
plMipmap *compressed = hsCodecManager::Instance().CreateCompressedMipmap(plMipmap::kDirectXCompression, hBitmap);
|
||||
// hsDXTSoftwareCodec::Instance().CreateCompressedBitmap(hBitmap);
|
||||
// hsDXTDirectXCodec::Instance().CreateCompressedBitmap(hBitmap);
|
||||
|
||||
if (compressed)
|
||||
{
|
||||
delete hBitmap;
|
||||
hBitmap = compressed;
|
||||
hBitmap->SetFlags( hBitmap->GetFlags() | flagsToSet );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hBitmap;
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Verify that bitmap is the correct type/size
|
||||
//
|
||||
void plBitmapCreator::ICheckOutBitmap(BitmapInfo* bInfo, Bitmap* bm, const char *fileName)
|
||||
{
|
||||
hsGuardBegin("hsConverterUtils::ICheckOutBitmap");
|
||||
|
||||
// Check out bitmap
|
||||
if (bm->Flags() & MAP_FLIPPED)
|
||||
MessageBox(GetActiveWindow(), "Bitmap is flipped horizontally", fileName, MB_OK);
|
||||
if (bm->Flags() & MAP_INVERTED)
|
||||
MessageBox(GetActiveWindow(), "Bitmap is inverted vertically", fileName, MB_OK);
|
||||
|
||||
if (bInfo->Flags() & MAP_FLIPPED)
|
||||
MessageBox(GetActiveWindow(), "BI:Bitmap is flipped horizontally", fileName, MB_OK);
|
||||
if (bInfo->Flags() & MAP_INVERTED)
|
||||
MessageBox(GetActiveWindow(), "BI:Bitmap is inverted vertically", fileName, MB_OK);
|
||||
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
int plBitmapCreator::IResampBitmap(Bitmap *bm, plMipmap &hBitmap)
|
||||
{
|
||||
hsGuardBegin("hsConverterUtils::IResampBitmap");
|
||||
|
||||
BitmapStorage *storage = bm->Storage();
|
||||
BitmapInfo *bInfo = &storage->bi;
|
||||
|
||||
int dbgW = bm->Width(), dbgH = bm->Height();
|
||||
int it;
|
||||
for( it = 1; it <= bm->Width(); it <<= 1 );
|
||||
it >>= 1;
|
||||
hBitmap.fWidth = it;
|
||||
for( it = 1; it <= bm->Height(); it <<= 1 );
|
||||
it >>= 1;
|
||||
hBitmap.fHeight = it;
|
||||
if( (hBitmap.fHeight >> 3) > hBitmap.fWidth )
|
||||
hBitmap.fHeight = hBitmap.fWidth << 3;
|
||||
else
|
||||
if( (hBitmap.fWidth >> 3) > hBitmap.fHeight )
|
||||
hBitmap.fWidth = hBitmap.fHeight << 3;
|
||||
|
||||
hBitmap.fPixelSize = 32;
|
||||
hBitmap.fRowBytes = hBitmap.fWidth * hBitmap.fPixelSize >> 3;
|
||||
hBitmap.fNumLevels = 1;
|
||||
|
||||
hBitmap.fImage = HSMemory::New(hBitmap.fRowBytes * hBitmap.fHeight);
|
||||
|
||||
#ifdef COLOR_BLACK_WHITE
|
||||
hBitmap.fFlags |= plMipmap::kColorWhite | plMipmap::kColorBlack;
|
||||
#endif // COLOR_BLACK_WHITE
|
||||
hBitmap.fFlags &= ~( plMipmap::kAlphaBitFlag | plMipmap::kAlphaChannelFlag );
|
||||
|
||||
int y,x;
|
||||
float scaleY, scaleX;
|
||||
hsRGBAColor32 *dstColor;
|
||||
dstColor = (hsRGBAColor32*)hBitmap.fImage;
|
||||
|
||||
scaleX = ((float)bm->Width())/(float)hBitmap.fWidth;
|
||||
scaleY = ((float)bm->Height())/(float)hBitmap.fHeight;
|
||||
for (y = 0; y < hBitmap.fHeight; y++)
|
||||
{
|
||||
for (x = 0; x < hBitmap.fWidth; x++)
|
||||
{
|
||||
BMM_Color_64 c64_00, c64_01, c64_10, c64_11;
|
||||
int ix, iy;
|
||||
float fracX, fracY;
|
||||
float t;
|
||||
t = x * scaleX;
|
||||
ix = (int)t;
|
||||
fracX = t-ix;
|
||||
t = y * scaleY;
|
||||
iy = (int)t;
|
||||
fracY = t-iy;
|
||||
|
||||
int ret = storage->GetPixels(ix,iy,1,&c64_00);
|
||||
// FIXME
|
||||
// fErrorMsg->Set(ret == 0, "ResampBitmap", "Failure getting pixels %dX%d", x, y).Check();
|
||||
ret = storage->GetPixels(ix+1,iy,1,&c64_10);
|
||||
ret = storage->GetPixels(ix,iy+1,1,&c64_01);
|
||||
ret = storage->GetPixels(ix+1,iy+1,1,&c64_11);
|
||||
|
||||
dstColor->r = (unsigned char)(255.0 / 65535.0
|
||||
* ( c64_00.r * (1.f - fracX) * (1.f - fracY)
|
||||
+ c64_10.r * ( fracX) * (1.f - fracY)
|
||||
+ c64_01.r * (1.f - fracX) * ( fracY)
|
||||
+ c64_11.r * ( fracX) * ( fracY) ));
|
||||
dstColor->g = (unsigned char)(255.0 / 65535.0
|
||||
* ( c64_00.g * (1.f - fracX) * (1.f - fracY)
|
||||
+ c64_10.g * ( fracX) * (1.f - fracY)
|
||||
+ c64_01.g * (1.f - fracX) * ( fracY)
|
||||
+ c64_11.g * ( fracX) * ( fracY) ));
|
||||
dstColor->b = (unsigned char)(255.0 / 65535.0
|
||||
* ( c64_00.b * (1.f - fracX) * (1.f - fracY)
|
||||
+ c64_10.b * ( fracX) * (1.f - fracY)
|
||||
+ c64_01.b * (1.f - fracX) * ( fracY)
|
||||
+ c64_11.b * ( fracX) * ( fracY) ));
|
||||
dstColor->a = (unsigned char)(255.0 / 65535.0
|
||||
* ( c64_00.a * (1.f - fracX) * (1.f - fracY)
|
||||
+ c64_10.a * ( fracX) * (1.f - fracY)
|
||||
+ c64_01.a * (1.f - fracX) * ( fracY)
|
||||
+ c64_11.a * ( fracX) * ( fracY) ));
|
||||
|
||||
|
||||
#ifdef COLOR_BLACK_WHITE
|
||||
if( dstColor->r | dstColor->g | dstColor->b )
|
||||
hBitmap.fFlags &= ~plMipmap::kColorBlack;
|
||||
if( ~(dstColor->r & dstColor->g & dstColor->b) )
|
||||
hBitmap.fFlags &= ~plMipmap::kColorWhite;
|
||||
#endif // COLOR_BLACK_WHITE
|
||||
|
||||
if( dstColor->a < 255 )
|
||||
{
|
||||
hBitmap.fFlags |= plMipmap::kAlphaBitFlag;
|
||||
if( dstColor->a > 0 )
|
||||
hBitmap.fFlags |= plMipmap::kAlphaChannelFlag;
|
||||
}
|
||||
dstColor++;
|
||||
}
|
||||
}
|
||||
if( hBitmap.fFlags & plMipmap::kAlphaChannelFlag )
|
||||
hBitmap.fFlags &= ~plMipmap::kAlphaBitFlag;
|
||||
|
||||
return 0;
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
int plBitmapCreator::ICopyBitmap(Bitmap *bm, plMipmap &hBitmap)
|
||||
{
|
||||
hsGuardBegin("hsConverterUtils::ICopyBitmap");
|
||||
|
||||
BitmapStorage *storage = bm->Storage();
|
||||
BitmapInfo *bInfo = &storage->bi;
|
||||
|
||||
hBitmap.fWidth = bm->Width();
|
||||
hBitmap.fHeight = bm->Height();
|
||||
hBitmap.fPixelSize = 32;
|
||||
hBitmap.fRowBytes = bm->Width()*hBitmap.fPixelSize/8;
|
||||
hBitmap.fNumLevels = 1;
|
||||
|
||||
hBitmap.fImage = HSMemory::New(hBitmap.fRowBytes * hBitmap.fHeight);
|
||||
|
||||
#ifdef COLOR_BLACK_WHITE
|
||||
hBitmap.fFlags |= plMipmap::kColorWhite | plMipmap::kColorBlack;
|
||||
#endif // COLOR_BLACK_WHITE
|
||||
hBitmap.fFlags &= ~( plMipmap::kAlphaBitFlag | plMipmap::kAlphaChannelFlag );
|
||||
|
||||
int y,x;
|
||||
hsRGBAColor32 *dstColor;
|
||||
dstColor = (hsRGBAColor32*)hBitmap.fImage;
|
||||
|
||||
for (y = 0; y < hBitmap.fHeight; y++)
|
||||
{
|
||||
for (x = 0; x < hBitmap.fWidth; x++)
|
||||
{
|
||||
BMM_Color_64 c64;
|
||||
int ret = storage->GetPixels(x,y,1,&c64);
|
||||
// FIXME
|
||||
// fErrorMsg->Set(ret == 0, "CopyBitmap", "Failure getting pixels %dX%d", x, y).Check();
|
||||
|
||||
// Convert from 16 bits to 8 bits
|
||||
dstColor->r = (char)(255.0*c64.r/65535.0);
|
||||
dstColor->g = (char)(255.0*c64.g/65535.0);
|
||||
dstColor->b = (char)(255.0*c64.b/65535.0);
|
||||
dstColor->a = (char)(255.0*c64.a/65535.0);
|
||||
|
||||
#ifdef COLOR_BLACK_WHITE
|
||||
if( dstColor->r | dstColor->g | dstColor->b )
|
||||
hBitmap.fFlags &= ~plMipmap::kColorBlack;
|
||||
if( ~(dstColor->r & dstColor->g & dstColor->b) )
|
||||
hBitmap.fFlags &= ~plMipmap::kColorWhite;
|
||||
#endif // COLOR_BLACK_WHITE
|
||||
|
||||
if( dstColor->a < 255 )
|
||||
{
|
||||
hBitmap.fFlags |= plMipmap::kAlphaBitFlag;
|
||||
if( dstColor->a > 0 )
|
||||
hBitmap.fFlags |= plMipmap::kAlphaChannelFlag;
|
||||
}
|
||||
dstColor++;
|
||||
}
|
||||
}
|
||||
if( hBitmap.fFlags & plMipmap::kAlphaChannelFlag )
|
||||
hBitmap.fFlags &= ~plMipmap::kAlphaBitFlag;
|
||||
|
||||
return 0;
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
int plBitmapCreator::IInvertAlpha(plMipmap& hBitmap)
|
||||
{
|
||||
hsGuardBegin("hsConverterUtils::ICopyBitmap");
|
||||
|
||||
hsAssert(hBitmap.fPixelSize == 32, "Only RGBA32 implemented");
|
||||
if( hBitmap.fPixelSize != 32 )
|
||||
return -1;
|
||||
|
||||
hsRGBAColor32* dstColor = (hsRGBAColor32*)hBitmap.fImage;
|
||||
int n = hBitmap.GetWidth() * hBitmap.GetHeight();
|
||||
int i;
|
||||
for( i = 0; i < n; i++ )
|
||||
{
|
||||
dstColor->a = 255 - dstColor->a;
|
||||
dstColor++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
plBitmap *plBitmapCreator::CreateTexture(plBitmapData *bd, const plLocation &loc, int clipID)
|
||||
{
|
||||
plBitmap* bm = ICreateTexture(bd, loc, clipID);
|
||||
|
||||
for (int i = 0; i < plLocalization::GetNumLocales(); i++)
|
||||
{
|
||||
char localName[MAX_PATH];
|
||||
if (plLocalization::ExportGetLocalized(bd->fileName, i, localName))
|
||||
{
|
||||
const char* oldName = bd->fileName;
|
||||
bd->fileName = localName;
|
||||
ICreateTexture(bd, loc, clipID);
|
||||
bd->fileName = oldName;
|
||||
}
|
||||
}
|
||||
|
||||
return bm;
|
||||
}
|
||||
|
||||
//// ICreateTexture ////////////////////////////////////////////////////////////
|
||||
// Plasma texture creator. Pass it a completed bitmapdata structure and it
|
||||
// returns a registered texture pointer, or nil if something goes wrong.
|
||||
//
|
||||
// 9.14.2001 mcn - clipID added to uniquely identify mipmaps that have been
|
||||
// rescaled differently (approximately represents how many powers of 2 it was
|
||||
// scaled down from the original source).
|
||||
//
|
||||
// 3.29.2002 mcn - Moved to plBitmapCreator, where it really belongs, and
|
||||
// added code to handle tracking/cleaning up all materials that are exported.
|
||||
|
||||
plBitmap *plBitmapCreator::ICreateTexture( plBitmapData *bd, const plLocation &loc, int clipID )
|
||||
{
|
||||
hsGuardBegin( "plBitmapCreator::CreateTexture" );
|
||||
|
||||
const plLocation &textureLoc = plPluginResManager::ResMgr()->GetCommonPage( loc, plAgeDescription::kTextures );
|
||||
|
||||
if( !bd )
|
||||
{
|
||||
fErrorMsg->Set( true, "Bitmap Error", "No bitmap data" ).Show();
|
||||
fErrorMsg->Set();
|
||||
return nil;
|
||||
}
|
||||
|
||||
if( bd->fileName == nil || bd->fileName[ 0 ] == 0 )
|
||||
{
|
||||
fErrorMsg->Set( true, "Bitmap Error", "Material texture has null bitmap name." ).Show();
|
||||
fErrorMsg->Set();
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Get and mangle key name
|
||||
char name[ 256 ], temp[ 256 ];
|
||||
_splitpath(bd->fileName, NULL, NULL, temp, NULL);
|
||||
|
||||
// Somehow, sometimes, we get the same file in with different cases. So we need to force the
|
||||
// case identical all the time, else the patching process for dat files will think they're
|
||||
// "different" when they're really not
|
||||
strlwr( temp );
|
||||
|
||||
/// Mangle name for detail textures, so we don't end up overwriting settings elsewhere
|
||||
if( bd->createFlags & plMipmap::kCreateDetailMask )
|
||||
{
|
||||
// Mangle of the form: name@dropStart&dropStop&max&min
|
||||
if( clipID != -1 )
|
||||
sprintf( name, "%s*%x#%d@%s&%3.2f&%3.2f&%3.2f&%3.2f", temp, bd->texFlags, clipID,
|
||||
bd->createFlags & plMipmap::kCreateDetailAlpha ? "al" : ( bd->createFlags & plMipmap::kCreateDetailAdd ? "ad" : "mu" ),
|
||||
bd->detailDropoffStart, bd->detailDropoffStop, bd->detailMax, bd->detailMin );
|
||||
else
|
||||
sprintf( name, "%s*%x@%s&%3.2f&%3.2f&%3.2f&%3.2f", temp, bd->texFlags,
|
||||
bd->createFlags & plMipmap::kCreateDetailAlpha ? "al" : ( bd->createFlags == plMipmap::kCreateDetailAdd ? "ad" : "mu" ),
|
||||
bd->detailDropoffStart, bd->detailDropoffStop, bd->detailMax, bd->detailMin );
|
||||
}
|
||||
else if( clipID != -1 )
|
||||
sprintf( name, "%s*%x#%d", temp, bd->texFlags, clipID );
|
||||
else
|
||||
sprintf( name, "%s*%x", temp, bd->texFlags );
|
||||
if( bd->invertAlpha )
|
||||
strcat( name, "_inva" );
|
||||
strcat( name, ".hsm" );
|
||||
|
||||
|
||||
// Has this texture been used before?
|
||||
plKey key;
|
||||
|
||||
plBitmap *texture = plBitmap::ConvertNoRef( sCommonBitmapLib.FindObject( name, ( bd->isStaticCubicEnvMap ) ? plCubicEnvironmap::Index() : plMipmap::Index() ) );
|
||||
//hsAssert( texture == nil || texture->GetKey()->GetUoid().GetLocation() == textureLoc, "Somehow our texture objectLib has a texture not in the right page? Should be harmless tho..." );
|
||||
|
||||
// Texture reuse optimization
|
||||
if( texture )
|
||||
{
|
||||
WIN32_FILE_ATTRIBUTE_DATA fileAttrib;
|
||||
GetFileAttributesEx(bd->fileName, GetFileExInfoStandard, &fileAttrib);
|
||||
FILETIME &fileTime = fileAttrib.ftLastWriteTime;
|
||||
|
||||
// If this texture has been modified since the last export, delete the old version but reuse the key
|
||||
if (!texture->IsSameModifiedTime(fileTime.dwLowDateTime, fileTime.dwHighDateTime))
|
||||
{
|
||||
DeleteExportedBitmap( texture->GetKey() );
|
||||
texture = nil;
|
||||
key = nil;
|
||||
}
|
||||
}
|
||||
|
||||
if( texture )
|
||||
{
|
||||
// If it's in the registry, great, use it.
|
||||
if( bd->texFlags & plMipmap::kNoMaxSize )
|
||||
texture->SetFlags( texture->GetFlags() | plMipmap::kNoMaxSize );
|
||||
|
||||
if( bd->texFlags & plMipmap::kHalfSize )
|
||||
texture->SetFlags( texture->GetFlags() | plMipmap::kHalfSize );
|
||||
}
|
||||
else
|
||||
{
|
||||
// If it hasn't been used before, make a new texture
|
||||
if( bd->isStaticCubicEnvMap )
|
||||
{
|
||||
plCubicEnvironmap *cubic = TRACKED_NEW plCubicEnvironmap;
|
||||
|
||||
plMipmap *face;
|
||||
|
||||
/// Build and set the faces
|
||||
bd->fileName = bd->faceNames[ plStaticEnvLayer::kTopFace ];
|
||||
face = ICreateBitmap( bd );
|
||||
if( face == nil ) return nil;
|
||||
cubic->CopyToFace( face, plCubicEnvironmap::kTopFace );
|
||||
|
||||
bd->fileName = bd->faceNames[ plStaticEnvLayer::kBottomFace ];
|
||||
face = ICreateBitmap( bd );
|
||||
if( face == nil ) return nil;
|
||||
cubic->CopyToFace( face, plCubicEnvironmap::kBottomFace );
|
||||
|
||||
bd->fileName = bd->faceNames[ plStaticEnvLayer::kLeftFace ];
|
||||
face = ICreateBitmap( bd );
|
||||
if( face == nil ) return nil;
|
||||
cubic->CopyToFace( face, plCubicEnvironmap::kLeftFace );
|
||||
|
||||
bd->fileName = bd->faceNames[ plStaticEnvLayer::kRightFace ];
|
||||
face = ICreateBitmap( bd );
|
||||
if( face == nil ) return nil;
|
||||
cubic->CopyToFace( face, plCubicEnvironmap::kRightFace );
|
||||
|
||||
/// NOTE: For whatever reason, MAX decided that the front and back faces should be'
|
||||
/// switched, literally. It's as if the cube for the cube map starts at the back face
|
||||
/// and then wraps around, instead of starting at the front face. Since we do things
|
||||
/// the RIGHT way (or rather, the front way :) on client-side, we need to flip the
|
||||
/// two here. If you convert this to the real MAX UI, make sure the faces are still
|
||||
/// flipped!!!!!!!!
|
||||
|
||||
bd->fileName = bd->faceNames[ plStaticEnvLayer::kBackFace ];
|
||||
face = ICreateBitmap( bd );
|
||||
if( face == nil ) return nil;
|
||||
cubic->CopyToFace( face, plCubicEnvironmap::kFrontFace );
|
||||
|
||||
bd->fileName = bd->faceNames[ plStaticEnvLayer::kFrontFace ];
|
||||
face = ICreateBitmap( bd );
|
||||
if( face == nil ) return nil;
|
||||
cubic->CopyToFace( face, plCubicEnvironmap::kBackFace );
|
||||
|
||||
|
||||
key = hsgResMgr::ResMgr()->NewKey( name, cubic, textureLoc );
|
||||
|
||||
texture = (plBitmap *)cubic;
|
||||
}
|
||||
else
|
||||
{
|
||||
plMipmap *mipmap = ICreateBitmap(bd);
|
||||
if (!mipmap)
|
||||
return nil;
|
||||
|
||||
key = hsgResMgr::ResMgr()->NewKey( name, mipmap, textureLoc );
|
||||
|
||||
texture = (plBitmap *)mipmap;
|
||||
}
|
||||
|
||||
// Texture reuse optimization
|
||||
WIN32_FILE_ATTRIBUTE_DATA fileAttrib;
|
||||
GetFileAttributesEx(bd->fileName, GetFileExInfoStandard, &fileAttrib);
|
||||
FILETIME &fileTime = fileAttrib.ftLastWriteTime;
|
||||
texture->SetModifiedTime(fileTime.dwLowDateTime, fileTime.dwHighDateTime);
|
||||
|
||||
// Add to our list of created textures and ref, since we have a hold of them
|
||||
IAddBitmap( texture );
|
||||
}
|
||||
|
||||
return texture;
|
||||
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
||||
//// IAddBitmap ///////////////////////////////////////////////////////////////
|
||||
|
||||
void plBitmapCreator::IAddBitmap( plBitmap *bitmap, hsBool dontRef )
|
||||
{
|
||||
sCommonBitmapLib.AddObject( bitmap );
|
||||
}
|
||||
|
||||
//// CreateBlankMipmap ////////////////////////////////////////////////////////
|
||||
// Simple mipmap creator, but importantly, it also adds the mipmap to the list
|
||||
// of "converted" maps to clean up at the end of export.
|
||||
|
||||
plMipmap *plBitmapCreator::CreateBlankMipmap( UInt32 width, UInt32 height, unsigned config, UInt8 numLevels,
|
||||
const char *keyName, const plLocation &keyLocation )
|
||||
{
|
||||
hsGuardBegin( "plBitmapCreator::CreateBlankMipmap" );
|
||||
|
||||
// Get our real location
|
||||
const plLocation &textureLoc = plPluginResManager::ResMgr()->GetCommonPage( keyLocation, plAgeDescription::kTextures );
|
||||
|
||||
// Is it already created?
|
||||
plKey key = hsgResMgr::ResMgr()->FindKey( plUoid( textureLoc, plMipmap::Index(), keyName ) );
|
||||
if( key != nil )
|
||||
return plMipmap::ConvertNoRef( key->GetObjectPtr() );
|
||||
|
||||
// Create
|
||||
plMipmap *mip = TRACKED_NEW plMipmap( width, height, config, numLevels );
|
||||
|
||||
// Assign key
|
||||
hsgResMgr::ResMgr()->NewKey( keyName, mip, textureLoc );
|
||||
|
||||
// Add to our list
|
||||
IAddBitmap( mip );
|
||||
|
||||
return mip;
|
||||
|
||||
hsGuardEnd;
|
||||
}
|
||||
|
129
Sources/Tools/MaxConvert/plBitmapCreator.h
Normal file
129
Sources/Tools/MaxConvert/plBitmapCreator.h
Normal file
@ -0,0 +1,129 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
#include "hsTypes.h"
|
||||
#include "../pnKeyedObject/plKey.h"
|
||||
|
||||
class BitmapInfo;
|
||||
class Bitmap;
|
||||
class plBitmap;
|
||||
class plMipmap;
|
||||
class hsMaxLayerBase;
|
||||
class plLocation;
|
||||
class plErrorMsg;
|
||||
|
||||
|
||||
class plBitmapData
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
kClampU = 0x01,
|
||||
kClampV = 0x02
|
||||
};
|
||||
|
||||
const char *fileName;
|
||||
UInt32 texFlags;
|
||||
UInt32 createFlags;
|
||||
hsScalar detailDropoffStart;
|
||||
hsScalar detailDropoffStop;
|
||||
hsScalar detailMax;
|
||||
hsScalar detailMin;
|
||||
float sig;
|
||||
hsBool isStaticCubicEnvMap;
|
||||
hsBool invertAlpha;
|
||||
const char *faceNames[ 6 ];
|
||||
UInt32 maxDimension;
|
||||
UInt8 clampFlags;
|
||||
bool useJPEG;
|
||||
|
||||
plBitmapData()
|
||||
{
|
||||
fileName = nil;
|
||||
texFlags = 0;
|
||||
createFlags = 0;
|
||||
detailDropoffStart = detailDropoffStop = 0.f;
|
||||
detailMax = detailMin = 0.f;
|
||||
sig = 0;
|
||||
isStaticCubicEnvMap = false;
|
||||
invertAlpha = false;
|
||||
faceNames[ 0 ] = faceNames[ 1 ] = faceNames[ 2 ] = faceNames[ 3 ] = faceNames[ 4 ] = faceNames[ 5 ] = nil;
|
||||
maxDimension = 0;
|
||||
clampFlags = 0;
|
||||
useJPEG = false;
|
||||
}
|
||||
};
|
||||
|
||||
class plRegistryKeyIterator;
|
||||
class plBitmapCreator
|
||||
{
|
||||
public:
|
||||
|
||||
static plBitmapCreator &Instance();
|
||||
|
||||
plBitmap *CreateTexture( plBitmapData *bd, const plLocation &loc, int clipID = -1 );
|
||||
plMipmap *CreateBlankMipmap( UInt32 width, UInt32 height, unsigned config, UInt8 numLevels, const char *keyName, const plLocation &keyLocation );
|
||||
|
||||
void Init( hsBool save, plErrorMsg *msg );
|
||||
void DeInit( void );
|
||||
void CleanUpMaps( void );
|
||||
|
||||
~plBitmapCreator();
|
||||
|
||||
// This will also set the key you pass in to nil, so be careful
|
||||
void DeleteExportedBitmap( const plKey &key );
|
||||
|
||||
protected:
|
||||
|
||||
plErrorMsg *fErrorMsg;
|
||||
|
||||
plBitmapCreator();
|
||||
|
||||
plBitmap *ICreateTexture( plBitmapData *bd, const plLocation &loc, int clipID = -1 );
|
||||
plMipmap *ICreateBitmap( plBitmapData *bd );
|
||||
|
||||
void ICheckOutBitmap( BitmapInfo *bInfo, Bitmap *bm, const char *fileName );
|
||||
int IResampBitmap( Bitmap *bm, plMipmap &hBitmap );
|
||||
int ICopyBitmap( Bitmap *bm, plMipmap &hBitmap );
|
||||
int IInvertAlpha( plMipmap &hBitmap );
|
||||
|
||||
void IAddBitmap( plBitmap *bitmap, hsBool dontRef = false );
|
||||
};
|
803
Sources/Tools/MaxConvert/plClusterUtil.cpp
Normal file
803
Sources/Tools/MaxConvert/plClusterUtil.cpp
Normal file
@ -0,0 +1,803 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#include "hsWindows.h"
|
||||
#include <commdlg.h>
|
||||
|
||||
#include "Max.h"
|
||||
#include "stdmat.h"
|
||||
#include "bmmlib.h"
|
||||
#include "iparamb2.h"
|
||||
#include "meshdlib.h"
|
||||
|
||||
#include "hsTypes.h"
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../MaxMain/plMaxNode.h"
|
||||
#include "../MaxComponent/plComponent.h"
|
||||
#include "../MaxComponent/plLightGrpComponent.h"
|
||||
#include "../MaxComponent/plSoftVolumeComponent.h"
|
||||
|
||||
#include "plClusterUtil.h"
|
||||
|
||||
#include "../plDrawable/plClusterGroup.h"
|
||||
#include "../plDrawable/plCluster.h"
|
||||
#include "../plDrawable/plSpanTemplate.h"
|
||||
#include "../plDrawable/plSpanInstance.h"
|
||||
#include "../plDrawable/plGeometrySpan.h"
|
||||
|
||||
#include "../plSurface/hsGMaterial.h"
|
||||
#include "../plSurface/plLayer.h"
|
||||
#include "../plScene/plVisRegion.h"
|
||||
#include "../plGLight/plLightInfo.h"
|
||||
|
||||
#include "plMeshConverter.h"
|
||||
#include "hsVertexShader.h"
|
||||
#include "plLightMapGen.h"
|
||||
|
||||
#include "hsResMgr.h"
|
||||
#include "../pnKeyedObject/plUoid.h"
|
||||
|
||||
#include "../pnMessage/plNodeRefMsg.h"
|
||||
|
||||
#include "plTweak.h"
|
||||
|
||||
plConst(int) kDefMinFaces(200);
|
||||
plConst(int) kDefMaxFaces(1000);
|
||||
plConst(hsScalar) kDefMinSize(50.f);
|
||||
|
||||
plClusterUtil::plClusterUtil()
|
||||
: fGroup(nil),
|
||||
fTemplNode(nil),
|
||||
fTemplate(nil),
|
||||
fMinFaces(kDefMinFaces),
|
||||
fMaxFaces(kDefMaxFaces),
|
||||
fMinSize(kDefMinSize),
|
||||
fIdx(0)
|
||||
{
|
||||
}
|
||||
|
||||
plClusterUtil::~plClusterUtil()
|
||||
{
|
||||
}
|
||||
|
||||
plClusterGroup* plClusterUtil::CreateGroup(plMaxNode* templNode, const char* name)
|
||||
{
|
||||
plClusterGroup* retVal = TRACKED_NEW plClusterGroup;
|
||||
|
||||
char buff[256];
|
||||
sprintf(buff, "%s_%s_%d", name, templNode->GetName(), fIdx++);
|
||||
hsgResMgr::ResMgr()->NewKey(buff, retVal, templNode->GetLocation(), templNode->GetLoadMask());
|
||||
|
||||
plKey sceneNode = templNode->GetRoomKey();
|
||||
retVal->SetSceneNode(sceneNode);
|
||||
|
||||
plNodeRefMsg* refMsg = TRACKED_NEW plNodeRefMsg(sceneNode, plRefMsg::kOnCreate, -1, plNodeRefMsg::kGeneric);
|
||||
hsgResMgr::ResMgr()->AddViaNotify(retVal->GetKey(), refMsg, plRefFlags::kActiveRef);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
plClusterGroup* plClusterUtil::SetupGroup(plClusterGroup *group, plMaxNode* templNode, plSpanTemplateB* templ)
|
||||
{
|
||||
fTemplNode = templNode;
|
||||
fGroup = group;
|
||||
fTemplate = templ;
|
||||
|
||||
fGroup->fTemplate = templ;
|
||||
fGroup->ISendToSelf(plClusterGroup::kRefMaterial, templ->fMaterial);
|
||||
|
||||
fGroup->fRenderLevel = templ->fRenderLevel;
|
||||
|
||||
fMinInsts = fMinFaces / templ->NumTris();
|
||||
fMaxInsts = fMaxFaces / templ->NumTris();
|
||||
if( fMinInsts < 1 )
|
||||
fMinInsts = 1;
|
||||
if( fMaxInsts <= fMinInsts )
|
||||
fMaxInsts = fMinInsts+1;
|
||||
|
||||
// STUB
|
||||
// Finish setting up the group here (lights, visregions, LOD), extracting all info
|
||||
// from the template node.
|
||||
ISetupGroupFromTemplate(templNode);
|
||||
|
||||
return fGroup;
|
||||
}
|
||||
|
||||
void plClusterUtil::ISetupGroupFromTemplate(plMaxNode* templ)
|
||||
{
|
||||
plLightGrpComponent* liGrp = plLightGrpComponent::GetComp(templ);
|
||||
if( liGrp )
|
||||
{
|
||||
const hsTArray<plLightInfo*>& lights = liGrp->GetLightInfos();
|
||||
int i;
|
||||
for( i = 0; i < lights.GetCount(); i++ )
|
||||
{
|
||||
fGroup->ISendToSelf(plClusterGroup::kRefLight, lights[i]);
|
||||
}
|
||||
}
|
||||
if( templ->HasFade() )
|
||||
{
|
||||
hsScalar maxDist = 0;
|
||||
hsScalar minDist = 0;
|
||||
|
||||
Box3 fade = templ->GetFade();
|
||||
const hsScalar kMaxMaxDist = 1.e10f;
|
||||
if( fade.Min()[2] < 0 )
|
||||
{
|
||||
minDist = fade.Min()[0];
|
||||
maxDist = kMaxMaxDist;
|
||||
}
|
||||
|
||||
if( fade.Max()[2] > 0 )
|
||||
maxDist = fade.Max()[0];
|
||||
|
||||
if( maxDist > minDist )
|
||||
{
|
||||
fGroup->fLOD.Set(minDist, maxDist);
|
||||
}
|
||||
}
|
||||
hsTArray<plVisRegion*> regions;
|
||||
plVisRegionComponent::CollectRegions(templ, regions);
|
||||
plEffVisSetComponent::CollectRegions(templ, regions);
|
||||
if( regions.GetCount() )
|
||||
{
|
||||
int i;
|
||||
for( i = 0; i < regions.GetCount(); i++ )
|
||||
{
|
||||
fGroup->ISendToSelf(plClusterGroup::kRefRegion, regions[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class sortData
|
||||
{
|
||||
public:
|
||||
UInt16 fIdx0;
|
||||
UInt16 fIdx1;
|
||||
UInt16 fIdx2;
|
||||
hsScalar fDist;
|
||||
|
||||
sortData() {}
|
||||
sortData(UInt16 idx0, UInt16 idx1, UInt16 idx2, hsScalar dist)
|
||||
: fIdx0(idx0), fIdx1(idx1), fIdx2(idx2), fDist(dist)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator<(const sortData& ot) const { return fDist < ot.fDist; }
|
||||
bool operator>(const sortData& ot) const { return fDist > ot.fDist; }
|
||||
bool operator==(const sortData& ot) const { return fDist == ot.fDist; }
|
||||
bool operator!=(const sortData& ot) const { return fDist != ot.fDist; }
|
||||
};
|
||||
|
||||
void plClusterUtil::ISortTemplate(plSpanTemplateB* templ) const
|
||||
{
|
||||
UInt16* indexData = templ->fIndices;
|
||||
const int numTris = templ->NumTris();
|
||||
typedef std::vector<sortData> sortVec;
|
||||
sortVec vec;
|
||||
vec.resize(numTris);
|
||||
sortVec::iterator iter;
|
||||
for( iter = vec.begin(); iter != vec.end(); iter++ )
|
||||
{
|
||||
iter->fIdx0 = indexData[0];
|
||||
iter->fIdx1 = indexData[1];
|
||||
iter->fIdx2 = indexData[2];
|
||||
hsPoint3 pos;
|
||||
pos = *templ->Position(indexData[0]);
|
||||
float dist0 = pos.fX * pos.fX + pos.fY * pos.fY;
|
||||
pos = *templ->Position(indexData[1]);
|
||||
float dist1 = pos.fX * pos.fX + pos.fY * pos.fY;
|
||||
pos = *templ->Position(indexData[2]);
|
||||
float dist2 = pos.fX * pos.fX + pos.fY * pos.fY;
|
||||
|
||||
iter->fDist = dist0 > dist1
|
||||
? (dist0 > dist2
|
||||
? dist0
|
||||
: dist2)
|
||||
: (dist1 > dist2
|
||||
? dist1
|
||||
: dist2);
|
||||
|
||||
indexData += 3;
|
||||
}
|
||||
|
||||
std::sort(vec.begin(), vec.end(), std::less<sortData>());
|
||||
|
||||
indexData = templ->fIndices;
|
||||
for( iter = vec.begin(); iter != vec.end(); iter++ )
|
||||
{
|
||||
indexData[0] = iter->fIdx0;
|
||||
indexData[1] = iter->fIdx1;
|
||||
indexData[2] = iter->fIdx2;
|
||||
|
||||
indexData += 3;
|
||||
}
|
||||
}
|
||||
|
||||
void plClusterUtil::ITemplateFromGeo(plSpanTemplateB* templ, plGeometrySpan* geo)
|
||||
{
|
||||
UInt16 format = plSpanTemplate::MakeFormat(
|
||||
true, // hasColor
|
||||
geo->GetNumUVs(), // UVW count
|
||||
geo->fFormat & plGeometrySpan::kSkinIndices, // hasWgtIdx
|
||||
(geo->fFormat & plGeometrySpan::kSkinWeightMask) >> 4, // NumWeights
|
||||
true, // hasNorm
|
||||
true // hasPos;
|
||||
);
|
||||
|
||||
|
||||
UInt32 numVerts = geo->fNumVerts;
|
||||
UInt32 numTris = geo->fNumIndices / 3;
|
||||
|
||||
// Alloc it.
|
||||
templ->Alloc(format, numVerts, numTris);
|
||||
templ->AllocColors();
|
||||
|
||||
UInt32 numPos = templ->NumPos();
|
||||
UInt32 numNorm = templ->NumNorm();
|
||||
UInt32 numUVWs = templ->NumUVWs();
|
||||
UInt32 numWeights = templ->NumWeights();
|
||||
UInt32 numColor = templ->NumColor();
|
||||
UInt32 numColor2 = templ->NumColor2();
|
||||
UInt32 numWgtIdx = templ->NumWgtIdx();
|
||||
|
||||
// Fill in the data.
|
||||
memcpy(templ->fIndices, geo->fIndexData, templ->IndexSize());
|
||||
|
||||
int i;
|
||||
for( i = 0; i < templ->NumVerts(); i++ )
|
||||
{
|
||||
float wgt[4];
|
||||
UInt32 wgtIdx;
|
||||
|
||||
geo->ExtractInitColor(i, templ->MultColor(i), templ->AddColor(i));
|
||||
|
||||
hsColorRGBA color;
|
||||
geo->ExtractVertex(i, templ->Position(i), templ->Normal(i), &color);
|
||||
|
||||
if( templ->NumColor() )
|
||||
*templ->Color(i) = color.ToARGB32();
|
||||
if( templ->NumColor2() )
|
||||
*templ->Color2(i) = 0;
|
||||
|
||||
int k;
|
||||
for( k = 0; k < templ->NumUVWs(); k++ )
|
||||
{
|
||||
geo->ExtractUv(i, k, templ->UVWs(i, k));
|
||||
}
|
||||
|
||||
if( templ->NumWeights() )
|
||||
{
|
||||
geo->ExtractWeights(i, wgt, &wgtIdx);
|
||||
int j;
|
||||
for( j = 0; j < templ->NumWeights(); j++ )
|
||||
*templ->Weight(i, j) = wgt[j];
|
||||
if( templ->NumWgtIdx() )
|
||||
*templ->WgtIdx(i) = wgtIdx;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the local bounds.
|
||||
templ->ComputeBounds();
|
||||
|
||||
ISortTemplate(templ);
|
||||
}
|
||||
|
||||
plSpanTemplateB* plClusterUtil::IAddTemplate(plMaxNode* templNode, plGeometrySpan* geo)
|
||||
{
|
||||
// Shade our mesh.
|
||||
// STUB
|
||||
|
||||
// Create our blank template
|
||||
plSpanTemplateB* templ = TRACKED_NEW plSpanTemplateB(templNode);
|
||||
|
||||
templ->fRenderLevel = templNode->GetRenderLevel(!templNode->GetNoDeferDraw());
|
||||
|
||||
ITemplateFromGeo(templ, geo);
|
||||
|
||||
return templ;
|
||||
}
|
||||
|
||||
void plClusterUtil::IAddTemplates(plMaxNode* templNode, plSpanTemplTab& templs)
|
||||
{
|
||||
// STUB
|
||||
// Get the Mesh
|
||||
|
||||
// Figure the format and total number of verts.
|
||||
// If we're lazy or pressed for time we could use MeshConverter.
|
||||
// But we'd probably spend more time undoing MeshConverter hacks than if we start
|
||||
// from scratch.
|
||||
// But, here we go descending cheerully into hell.
|
||||
// At least with this interface we can bail and do it right later without to much
|
||||
// bloodshed.
|
||||
hsTArray<plGeometrySpan*> spanArray;
|
||||
if( !plMeshConverter::Instance().CreateSpans(templNode, spanArray, false) )
|
||||
return;
|
||||
|
||||
plLightMapGen::Instance().Open(::GetCOREInterface(), ::GetCOREInterface()->GetTime(), false);
|
||||
hsVertexShader::Instance().Open();
|
||||
|
||||
hsVertexShader::Instance().ShadeNode(templNode,
|
||||
templNode->GetLocalToWorld44(), templNode->GetWorldToLocal44(),
|
||||
spanArray);
|
||||
|
||||
plLightMapGen::Instance().Close();
|
||||
hsVertexShader::Instance().Close();
|
||||
|
||||
int i;
|
||||
for( i = 0; i < spanArray.GetCount(); i++ )
|
||||
{
|
||||
plSpanTemplateB* templ = IAddTemplate(templNode, spanArray[i]);
|
||||
templs.Append(1, &templ);
|
||||
templ->fMaterial = spanArray[i]->fMaterial;
|
||||
|
||||
delete spanArray[i];
|
||||
}
|
||||
}
|
||||
|
||||
Box3 plClusterUtil::IBound(const plL2WTab& src) const
|
||||
{
|
||||
Box3 box;
|
||||
int i;
|
||||
for( i = 0; i < src.Count(); i++ )
|
||||
{
|
||||
box += src[i].GetTrans();
|
||||
}
|
||||
return box;
|
||||
}
|
||||
|
||||
Point3 plClusterUtil::ILength(const plL2WTab& src) const
|
||||
{
|
||||
Box3 box = IBound(src);
|
||||
return box.Max() - box.Min();
|
||||
}
|
||||
|
||||
int plClusterUtil::ISelectAxis(const plL2WTab& src) const
|
||||
{
|
||||
Box3 box = IBound(src);
|
||||
Point3 del = box.Max() - box.Min();
|
||||
if( del.x > del.y )
|
||||
{
|
||||
if( del.x > del.z )
|
||||
return 0;
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
if( del.y > del.z )
|
||||
return 1;
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
static int sortAxis = 0;
|
||||
static int cmp(const void *elem1, const void *elem2)
|
||||
{
|
||||
Matrix3* m1 = (Matrix3*) elem1;
|
||||
Matrix3* m2 = (Matrix3*) elem2;
|
||||
|
||||
float d1 = m1->GetTrans()[sortAxis];
|
||||
float d2 = m2->GetTrans()[sortAxis];
|
||||
|
||||
if( d1 < d2 )
|
||||
return -1;
|
||||
else if( d1 > d2 )
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
hsBool plClusterUtil::ISplitCluster(plSpanTemplateB* templ, plL2WTab& src, plL2WTab& lo, plL2WTab& hi)
|
||||
{
|
||||
// Tried this, seems to work pretty well, but a more even grid is probably wiser at
|
||||
// this point.
|
||||
#if 0 // MAX_SEP
|
||||
if( src.Count() <= fMinInsts)
|
||||
return false;
|
||||
|
||||
// Pick an axis
|
||||
sortAxis = ISelectAxis(src);
|
||||
|
||||
if( src.Count() < fMaxInsts)
|
||||
{
|
||||
Point3 len = ILength(src);
|
||||
if( len[sortAxis] < fMinSize )
|
||||
return false;
|
||||
}
|
||||
|
||||
// Sort by that axis
|
||||
src.Sort(cmp);
|
||||
|
||||
// Find the biggest gap
|
||||
float maxDist = 0;
|
||||
int pivot = 0;
|
||||
int i;
|
||||
for( i = 1; i < src.Count(); i++ )
|
||||
{
|
||||
float dist = src[i].GetTrans()[sortAxis] - src[i-1].GetTrans()[sortAxis];
|
||||
if( dist > maxDist )
|
||||
{
|
||||
maxDist = dist;
|
||||
pivot = i;
|
||||
}
|
||||
}
|
||||
hsAssert((pivot > 0) && (pivot < src.Count()), "Invalid pivot found");
|
||||
|
||||
// Put everyone above it in hi, below it in lo
|
||||
lo.Append(pivot, src.Addr(0));
|
||||
hi.Append(src.Count()-pivot, src.Addr(pivot));
|
||||
|
||||
#else // MAX_SEP
|
||||
|
||||
if( src.Count() <= fMinInsts )
|
||||
return false;
|
||||
|
||||
// Pick an axis
|
||||
sortAxis = ISelectAxis(src);
|
||||
|
||||
if( src.Count() < fMaxInsts)
|
||||
{
|
||||
Point3 len = ILength(src);
|
||||
if( len[sortAxis] < fMinSize )
|
||||
return false;
|
||||
}
|
||||
|
||||
// Sort by that axis
|
||||
src.Sort(cmp);
|
||||
|
||||
int pivot = src.Count() >> 1;
|
||||
lo.Append(pivot, src.Addr(0));
|
||||
hi.Append(src.Count()-pivot, src.Addr(pivot));
|
||||
#endif // MAX_SEP
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void plClusterUtil::IFindClustersRecur(plSpanTemplateB* templ, plL2WTab& src, plL2WTabTab& dst)
|
||||
{
|
||||
plL2WTab lo;
|
||||
plL2WTab hi;
|
||||
|
||||
if( ISplitCluster(templ, src, lo, hi) )
|
||||
{
|
||||
// Keep going
|
||||
IFindClustersRecur(templ, lo, dst);
|
||||
IFindClustersRecur(templ, hi, dst);
|
||||
}
|
||||
else
|
||||
{
|
||||
plL2WTab* tab = TRACKED_NEW plL2WTab(src);
|
||||
dst.Append(1, &tab);
|
||||
}
|
||||
}
|
||||
|
||||
void plClusterUtil::IFreeClustersRecur(plL2WTabTab& dst) const
|
||||
{
|
||||
int i;
|
||||
for( i = 0; i < dst.Count(); i++ )
|
||||
delete dst[i];
|
||||
}
|
||||
|
||||
inline hsScalar inlGetAlpha(UInt32* color)
|
||||
{
|
||||
return hsScalar(*color >> 24) / 255.99f;
|
||||
}
|
||||
|
||||
plSpanEncoding plClusterUtil::ISelectEncoding(plPoint3TabTab& delPosTab, plColorTabTab& colorsTab)
|
||||
{
|
||||
hsBool hasColor = false;
|
||||
hsBool hasAlpha = false;
|
||||
hsScalar maxLenSq = 0;
|
||||
hsScalar maxX = 0;
|
||||
hsScalar maxY = 0;
|
||||
hsScalar maxZ = 0;
|
||||
int i;
|
||||
for( i = 0; i < delPosTab.Count(); i++ )
|
||||
{
|
||||
int j;
|
||||
if( delPosTab[i] )
|
||||
{
|
||||
plPoint3Tab& delPos = *delPosTab[i];
|
||||
for( j = 0; j < delPos.Count(); j++ )
|
||||
{
|
||||
hsScalar lenSq = delPos[j].MagnitudeSquared();
|
||||
if( lenSq > maxLenSq )
|
||||
maxLenSq = lenSq;
|
||||
hsScalar d = fabs(delPos[j].fX);
|
||||
if( d > maxX )
|
||||
maxX = d;
|
||||
d = fabs(delPos[j].fY);
|
||||
if( d > maxY )
|
||||
maxY = d;
|
||||
d = fabs(delPos[j].fZ);
|
||||
if( d > maxZ )
|
||||
maxZ = d;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if( colorsTab[i] )
|
||||
{
|
||||
plColorTab& color = *colorsTab[i];
|
||||
for( j = 0; j < color.Count(); j++ )
|
||||
{
|
||||
UInt32 col = color[j];
|
||||
if( (col & 0x00ffffff) != 0x00ffffff )
|
||||
hasColor = true;
|
||||
if( (col & 0xff000000) != 0xff000000 )
|
||||
hasAlpha = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 code = 0;
|
||||
hsScalar posScale = 1.f;
|
||||
|
||||
if( hasColor && hasAlpha )
|
||||
code |= plSpanEncoding::kColAI88;
|
||||
else if( hasColor )
|
||||
code |= plSpanEncoding::kColI8;
|
||||
else if( hasAlpha )
|
||||
code |= plSpanEncoding::kColA8;
|
||||
|
||||
plConst(hsScalar) kPosQuantum(0.5 / 12.f); // 1/2 inch.
|
||||
hsScalar maxLen = hsSquareRoot(maxLenSq);
|
||||
if( maxLen > kPosQuantum )
|
||||
{
|
||||
if( (maxX < kPosQuantum) && (maxY < kPosQuantum) )
|
||||
{
|
||||
code |= plSpanEncoding::kPos008;
|
||||
posScale = maxLen / 255.9f;
|
||||
}
|
||||
else if( (maxLen / 255.9f) < kPosQuantum )
|
||||
{
|
||||
code |= plSpanEncoding::kPos888;
|
||||
posScale = maxLen / 255.9f;
|
||||
}
|
||||
else if( (maxLen / hsScalar(1 << 10)) < kPosQuantum )
|
||||
{
|
||||
code |= plSpanEncoding::kPos101010;
|
||||
posScale = maxLen / hsScalar(1 << 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
code |= plSpanEncoding::kPos161616;
|
||||
posScale = maxLen / hsScalar(1 << 16);
|
||||
}
|
||||
}
|
||||
return plSpanEncoding(code, posScale);
|
||||
}
|
||||
|
||||
static int CompTemplates(const void *elem1, const void *elem2)
|
||||
{
|
||||
plSpanTemplateB* templA = *((plSpanTemplateB**)elem1);
|
||||
plSpanTemplateB* templB = *((plSpanTemplateB**)elem2);
|
||||
|
||||
hsScalar hA = templA->GetLocalBounds().GetMaxs().fZ;
|
||||
hsScalar hB = templB->GetLocalBounds().GetMaxs().fZ;
|
||||
|
||||
if( hA < hB )
|
||||
return -1;
|
||||
|
||||
if( hA > hB )
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void plClusterUtil::ISortTemplates(plSpanTemplTab& templs) const
|
||||
{
|
||||
templs.Sort(CompTemplates);
|
||||
|
||||
float maxZ = -1.e33f;
|
||||
|
||||
int i;
|
||||
for( i = 1; i < templs.Count(); i++ )
|
||||
{
|
||||
templs[i]->fRenderLevel.Set(templs[i-1]->fRenderLevel.Level() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
plSpanTemplTab plClusterUtil::MakeTemplates(INode* templNode)
|
||||
{
|
||||
plSpanTemplTab templs;
|
||||
IAddTemplates((plMaxNode*)templNode, templs);
|
||||
ISortTemplates(templs);
|
||||
return templs;
|
||||
}
|
||||
|
||||
void plClusterUtil::AddClusters(plL2WTab& insts, plDeformVert* def, plShadeVert* shade)
|
||||
{
|
||||
plPoint3TabTab delPos;
|
||||
plColorTabTab colors;
|
||||
|
||||
plL2WTabTab clusters;
|
||||
IFindClustersRecur(fTemplate, insts, clusters);
|
||||
|
||||
int j;
|
||||
for( j = 0; j < clusters.Count(); j++ )
|
||||
{
|
||||
// Create a plCluster to hold them all.
|
||||
plCluster* cluster = fGroup->IAddCluster();
|
||||
|
||||
// Get the delPositions and colors for all the instances
|
||||
IAllocPosAndColor(fTemplate, *clusters[j], delPos, colors);
|
||||
|
||||
IDelPosAndColor(fTemplate,
|
||||
*clusters[j],
|
||||
def, shade,
|
||||
delPos, colors);
|
||||
|
||||
|
||||
// Look through the results and pick out a proper encoding
|
||||
plSpanEncoding code = ISelectEncoding(delPos, colors);
|
||||
cluster->SetEncoding(code);
|
||||
|
||||
// Now create, encode and add all the insts to the cluster.
|
||||
IAddInstsToCluster(cluster, fTemplate, *clusters[j], delPos, colors);
|
||||
|
||||
IFreePosAndColor(delPos, colors);
|
||||
}
|
||||
|
||||
IFreeClustersRecur(clusters);
|
||||
}
|
||||
|
||||
void plClusterUtil::IAddInstsToCluster(plCluster* cluster, plSpanTemplateB* templ,
|
||||
const plL2WTab& insts,
|
||||
plPoint3TabTab& delPos,
|
||||
plColorTabTab& colors)
|
||||
{
|
||||
int i;
|
||||
for( i = 0; i < insts.Count(); i++ )
|
||||
{
|
||||
plSpanInstance* span = TRACKED_NEW plSpanInstance;
|
||||
span->Alloc(cluster->GetEncoding(), templ->NumVerts());
|
||||
|
||||
span->SetLocalToWorld(plMaxNodeBase::Matrix3ToMatrix44(insts[i]));
|
||||
|
||||
span->Encode(cluster->GetEncoding(), templ->NumVerts(),
|
||||
delPos[i] ? delPos[i]->Addr(0) : nil,
|
||||
colors[i] ? colors[i]->Addr(0) : nil);
|
||||
|
||||
cluster->IAddInst(span);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void plClusterUtil::IAllocPosAndColor(plSpanTemplateB* templ, const plL2WTab& insts,
|
||||
plPoint3TabTab& delPos, plColorTabTab& colors)
|
||||
{
|
||||
delPos.SetCount(insts.Count());
|
||||
colors.SetCount(insts.Count());
|
||||
|
||||
const int numVerts = templ->NumVerts();
|
||||
int i;
|
||||
for( i = 0; i < insts.Count(); i++ )
|
||||
{
|
||||
delPos[i] = nil;
|
||||
colors[i] = nil;
|
||||
}
|
||||
}
|
||||
|
||||
void plClusterUtil::IFreePosAndColor(plPoint3TabTab& delPos, plColorTabTab& colors) const
|
||||
{
|
||||
int i;
|
||||
for( i = 0; i < delPos.Count(); i++ )
|
||||
delete delPos[i];
|
||||
for( i = 0; i < colors.Count(); i++ )
|
||||
delete colors[i];
|
||||
}
|
||||
|
||||
void plClusterUtil::IDelPosAndColor(plSpanTemplateB* templ,
|
||||
const plL2WTab& insts, plDeformVert* def, plShadeVert* shade,
|
||||
plPoint3TabTab& delPos, plColorTabTab& colors)
|
||||
{
|
||||
|
||||
hsBool doDef = def != nil;
|
||||
hsBool doCol = shade != nil;
|
||||
// For each inst
|
||||
int i;
|
||||
for( i = 0; i < insts.Count(); i++ )
|
||||
{
|
||||
hsBounds3Ext wBnd = templ->GetLocalBounds();
|
||||
hsMatrix44 l2w = plMaxNodeBase::Matrix3ToMatrix44(insts[i]);
|
||||
hsMatrix44 w2l;
|
||||
l2w.GetInverse(&w2l);
|
||||
hsMatrix44 w2lT;
|
||||
w2l.GetTranspose(&w2lT);
|
||||
|
||||
wBnd.Transform(&l2w);
|
||||
|
||||
if( doDef )
|
||||
{
|
||||
def->Begin(templ->GetSrcNode(), wBnd);
|
||||
|
||||
delPos[i] = TRACKED_NEW plPoint3Tab;
|
||||
delPos[i]->SetCount(templ->NumVerts());
|
||||
int j;
|
||||
for( j = 0; j < templ->NumVerts(); j++ )
|
||||
{
|
||||
hsPoint3 p = l2w * *templ->Position(j);
|
||||
plPoint3Tab& dp = *delPos[i];
|
||||
dp[j] = def->GetDel(p);
|
||||
dp[j] = w2l * dp[j];
|
||||
}
|
||||
|
||||
def->End();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Make the stored colors the actual output UInt32.
|
||||
// templ has the mult and add colors, apply them here.
|
||||
if( doCol )
|
||||
{
|
||||
shade->Begin(templ->GetSrcNode(), wBnd);
|
||||
|
||||
colors[i] = TRACKED_NEW plColorTab;
|
||||
colors[i]->SetCount(templ->NumVerts());
|
||||
int j;
|
||||
for( j = 0; j < templ->NumVerts(); j++ )
|
||||
{
|
||||
hsPoint3 pos = *templ->Position(j);
|
||||
pos += (*delPos[i])[j];
|
||||
pos = l2w * pos;
|
||||
|
||||
hsVector3 norm = *templ->Normal(j);
|
||||
norm = w2lT * norm;
|
||||
|
||||
Color rgb = shade->GetShade(pos, norm);
|
||||
|
||||
rgb *= Color(templ->MultColor(j)->r, templ->MultColor(j)->g, templ->MultColor(j)->b);
|
||||
rgb += Color(templ->AddColor(j)->r, templ->AddColor(j)->g, templ->AddColor(j)->b);
|
||||
|
||||
(*colors[i])[j] = hsColorRGBA().Set(rgb.r, rgb.g, rgb.b, templ->MultColor(j)->a).ToARGB32();
|
||||
}
|
||||
shade->End();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
150
Sources/Tools/MaxConvert/plClusterUtil.h
Normal file
150
Sources/Tools/MaxConvert/plClusterUtil.h
Normal file
@ -0,0 +1,150 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#ifndef plClusterUtil_inc
|
||||
#define plClusterUtil_inc
|
||||
|
||||
#include "hsGeometry3.h"
|
||||
#include "hsColorRGBA.h"
|
||||
|
||||
#include "../plDrawable/plSpanInstance.h"
|
||||
|
||||
class plMaxNode;
|
||||
class plClusterGroup;
|
||||
class plSpanTemplateB;
|
||||
class hsBounds3Ext;
|
||||
class plCluster;
|
||||
class hsGMaterial;
|
||||
|
||||
class plDeformVert
|
||||
{
|
||||
public:
|
||||
|
||||
// Begin returns true if it's actually planning to do anything.
|
||||
// If it returns false, End will still get called, but GetDel probably won't.
|
||||
virtual hsBool Begin(INode* templNode, const hsBounds3Ext& wBnd) { return false; }
|
||||
virtual void End() {}
|
||||
|
||||
hsVector3 GetDel(const hsPoint3& p) { return GetDel(Point3(p.fX, p.fY, p.fZ)); }
|
||||
virtual hsVector3 GetDel(const Point3& p) { return hsVector3(0,0,0); }
|
||||
};
|
||||
|
||||
class plShadeVert
|
||||
{
|
||||
public:
|
||||
virtual hsBool Begin(INode* templNode, const hsBounds3Ext& wBnd) { return false; }
|
||||
virtual void End() {}
|
||||
|
||||
Color GetShade(const hsPoint3& p, const hsVector3& n) { return GetShade(Point3(p.fX, p.fY, p.fZ), Point3(n.fX, n.fY, n.fZ)); }
|
||||
virtual Color GetShade(const Point3& p, const Point3& n) { return Color(0,0,0); }
|
||||
};
|
||||
|
||||
class plL2WTab : public Tab<Matrix3> {};
|
||||
class plL2WTabTab : public Tab<plL2WTab*> {};
|
||||
|
||||
class plPoint3Tab : public Tab<hsVector3> {};
|
||||
class plPoint3TabTab : public Tab<plPoint3Tab*> {};
|
||||
|
||||
class plColorTab : public Tab<UInt32> {};
|
||||
class plColorTabTab : public Tab<plColorTab*> {};
|
||||
|
||||
class plSpanTemplTab : public Tab<plSpanTemplateB*> {};
|
||||
|
||||
class plClusterUtil
|
||||
{
|
||||
protected:
|
||||
UInt32 fIdx;
|
||||
plClusterGroup* fGroup;
|
||||
plMaxNode* fTemplNode;
|
||||
plSpanTemplateB* fTemplate;
|
||||
|
||||
int fMinFaces;
|
||||
int fMaxFaces;
|
||||
hsScalar fMinSize;
|
||||
|
||||
int fMinInsts;
|
||||
int fMaxInsts;
|
||||
|
||||
|
||||
plSpanEncoding ISelectEncoding(plPoint3TabTab& delPos, plColorTabTab& colors);
|
||||
void IAllocPosAndColor(plSpanTemplateB* templ, const plL2WTab& insts,
|
||||
plPoint3TabTab& delPos, plColorTabTab& colors);
|
||||
void IDelPosAndColor(plSpanTemplateB* templ,
|
||||
const plL2WTab& insts, plDeformVert* def, plShadeVert* shade,
|
||||
plPoint3TabTab& delPos, plColorTabTab& colors);
|
||||
void IAddInstsToCluster(plCluster* cluster, plSpanTemplateB* templ,
|
||||
const plL2WTab& insts,
|
||||
plPoint3TabTab& delPos,
|
||||
plColorTabTab& colors);
|
||||
void IFreePosAndColor(plPoint3TabTab& delPos, plColorTabTab& colors) const;
|
||||
|
||||
void IFreeClustersRecur(plL2WTabTab& dst) const;
|
||||
void IFindClustersRecur(plSpanTemplateB* templ, plL2WTab& src, plL2WTabTab& dst);
|
||||
hsBool ISplitCluster(plSpanTemplateB* templ, plL2WTab& src, plL2WTab& lo, plL2WTab& hi);
|
||||
int ISelectAxis(const plL2WTab& src) const;
|
||||
Box3 IBound(const plL2WTab& src) const;
|
||||
Point3 ILength(const plL2WTab& src) const;
|
||||
|
||||
void ISortTemplate(plSpanTemplateB* templ) const;
|
||||
plSpanTemplateB* IAddTemplate(plMaxNode* templNode, plGeometrySpan* geo);
|
||||
void ITemplateFromGeo(plSpanTemplateB* templ, plGeometrySpan* geo);
|
||||
|
||||
void ISortTemplates(plSpanTemplTab& templs) const;
|
||||
void IAddTemplates(plMaxNode* templNode, plSpanTemplTab& templs);
|
||||
|
||||
void ISetupGroupFromTemplate(plMaxNode* templ);
|
||||
|
||||
public:
|
||||
plClusterUtil();
|
||||
~plClusterUtil();
|
||||
|
||||
plSpanTemplTab MakeTemplates(INode* templNode);
|
||||
|
||||
plClusterGroup* CreateGroup(plMaxNode* node, const char* name);
|
||||
plClusterGroup* SetupGroup(plClusterGroup* group, plMaxNode* node, plSpanTemplateB* templ);
|
||||
plClusterGroup* GetGroup() const { return fGroup; }
|
||||
|
||||
void AddClusters(plL2WTab& insts, plDeformVert* def, plShadeVert* shade);
|
||||
|
||||
};
|
||||
|
||||
#endif // plClusterUtil_inc
|
514
Sources/Tools/MaxConvert/plConvert.cpp
Normal file
514
Sources/Tools/MaxConvert/plConvert.cpp
Normal file
@ -0,0 +1,514 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
//
|
||||
// 3DSMax HeadSpin exporter
|
||||
//
|
||||
#include "hsTypes.h"
|
||||
#include "Max.h"
|
||||
#include "istdplug.h"
|
||||
#include "Notify.h"
|
||||
#include <commdlg.h>
|
||||
#include "bmmlib.h"
|
||||
#include "INode.h"
|
||||
|
||||
#include "plConvert.h"
|
||||
#include "hsResMgr.h"
|
||||
#include "hsTemplates.h"
|
||||
|
||||
#include "hsConverterUtils.h"
|
||||
#include "hsControlConverter.h"
|
||||
#include "plMeshConverter.h"
|
||||
#include "hsMaterialConverter.h"
|
||||
#include "plLayerConverter.h"
|
||||
#include "UserPropMgr.h"
|
||||
#include "hsStringTokenizer.h"
|
||||
#include "../MaxExport/plErrorMsg.h"
|
||||
#include "hsVertexShader.h"
|
||||
#include "plLightMapGen.h"
|
||||
#include "plBitmapCreator.h"
|
||||
#include "plgDispatch.h"
|
||||
|
||||
#include "../pnMessage/plTimeMsg.h"
|
||||
#include "../MaxComponent/plComponent.h"
|
||||
#include "../MaxMain/plMaxNode.h"
|
||||
#include "../plMessage/plNodeCleanupMsg.h"
|
||||
#include "../pnSceneObject/plSceneObject.h"
|
||||
#include "../MaxComponent/plClusterComponent.h"
|
||||
|
||||
#include "../plPhysX/plSimulationMgr.h"
|
||||
#include "../MaxMain/plPhysXCooking.h"
|
||||
#include "../MaxExport/plExportProgressBar.h"
|
||||
#include "hsUtils.h"
|
||||
|
||||
#include "../MaxMain/plGetLocationDlg.h"
|
||||
|
||||
#ifdef HS_DEBUGGING
|
||||
#define HS_NO_TRY
|
||||
#endif
|
||||
|
||||
plConvert::plConvert() : fWarned(0)
|
||||
{
|
||||
}
|
||||
|
||||
plConvert& plConvert::Instance()
|
||||
{
|
||||
static plConvert theInstance;
|
||||
return theInstance;
|
||||
}
|
||||
|
||||
hsBool plConvert::IOK()
|
||||
{
|
||||
return (!fQuit && !fpErrorMsg->IsBogus() ) ? true: false;
|
||||
}
|
||||
|
||||
hsBool plConvert::Convert()
|
||||
{
|
||||
#ifndef HS_NO_TRY
|
||||
try
|
||||
#endif
|
||||
{
|
||||
fSettings->fReconvert = false;
|
||||
fWarned = 0;
|
||||
|
||||
fInterface->SetIncludeXRefsInHierarchy(TRUE);
|
||||
|
||||
plMaxNode *pNode = (plMaxNode *)fInterface->GetRootNode();
|
||||
AddMessageToQueue(new plTransformMsg(nil, nil, nil, nil));
|
||||
AddMessageToQueue(new plDelayedTransformMsg(nil, nil, nil, nil));
|
||||
|
||||
IFindDuplicateNames();
|
||||
|
||||
plExportProgressBar bar;
|
||||
hsBool retVal = true; // sometime, we might look at this
|
||||
|
||||
if( !IAutoClusterRecur(pNode) )
|
||||
{
|
||||
fQuit = true;
|
||||
}
|
||||
|
||||
if(IOK())
|
||||
{
|
||||
bar.Start("Clear Old Data");
|
||||
retVal = pNode->DoAllRecur( plMaxNode::ClearData, fpErrorMsg, fSettings, &bar );
|
||||
}
|
||||
if(IOK())
|
||||
{
|
||||
bar.Start("Convert Validate");
|
||||
retVal = pNode->DoRecur( plMaxNode::ConvertValidate, fpErrorMsg, fSettings, &bar );
|
||||
}
|
||||
if(IOK())
|
||||
{
|
||||
bar.Start("Components Initialize");
|
||||
retVal = pNode->DoRecur( plMaxNode::SetupPropertiesPass, fpErrorMsg, fSettings, &bar );
|
||||
}
|
||||
if(IOK())
|
||||
{
|
||||
bar.Start("Prepare for skinning");
|
||||
retVal = pNode->DoRecur( plMaxNode::PrepareSkin, fpErrorMsg, fSettings, &bar );
|
||||
}
|
||||
if(IOK())
|
||||
{
|
||||
bar.Start("Make Scene Object");
|
||||
retVal = pNode->DoRecur( plMaxNode::MakeSceneObject, fpErrorMsg, fSettings, &bar );
|
||||
}
|
||||
if(IOK())
|
||||
{
|
||||
bar.Start("Make Physical");
|
||||
plPhysXCooking::Init();
|
||||
retVal = pNode->DoRecur( plMaxNode::MakePhysical, fpErrorMsg, fSettings, &bar );
|
||||
plPhysXCooking::Shutdown();
|
||||
}
|
||||
if(IOK())
|
||||
{
|
||||
bar.Start("Component Preconvert");
|
||||
retVal = pNode->DoRecur( plMaxNode::FirstComponentPass, fpErrorMsg, fSettings, &bar );
|
||||
}
|
||||
if(IOK())
|
||||
{
|
||||
bar.Start("Make Controller");
|
||||
retVal = pNode->DoRecur( plMaxNode::MakeController, fpErrorMsg, fSettings, &bar );
|
||||
}
|
||||
if(IOK())
|
||||
{ // must be before mesh
|
||||
bar.Start("Make Coord Interface");
|
||||
retVal = pNode->DoRecur( plMaxNode::MakeCoordinateInterface, fpErrorMsg, fSettings, &bar );
|
||||
}
|
||||
if(IOK())
|
||||
{ // must be after coord interface but before pool data is created.
|
||||
bar.Start("Make Connections");
|
||||
retVal = pNode->DoRecur( plMaxNode::MakeParentOrRoomConnection, fpErrorMsg, fSettings, &bar );
|
||||
}
|
||||
|
||||
if(IOK())
|
||||
{ // must be before simulation
|
||||
bar.Start("Make Mesh");
|
||||
retVal = pNode->DoRecur( plMaxNode::MakeMesh, fpErrorMsg, fSettings, &bar );
|
||||
}
|
||||
|
||||
if(IOK())
|
||||
{ // doesn't matter when
|
||||
bar.Start("Make Light");
|
||||
retVal = pNode->DoRecur( plMaxNode::MakeLight, fpErrorMsg, fSettings, &bar );
|
||||
}
|
||||
if(IOK())
|
||||
{ // doesn't matter when
|
||||
bar.Start("Make Occluder");
|
||||
retVal = pNode->DoRecur( plMaxNode::MakeOccluder, fpErrorMsg, fSettings, &bar );
|
||||
}
|
||||
if(IOK())
|
||||
{ // must be after mesh
|
||||
bar.Start("Make Modifiers");
|
||||
retVal = pNode->DoRecur( plMaxNode::MakeModifiers, fpErrorMsg, fSettings, &bar );
|
||||
}
|
||||
if(IOK())
|
||||
{
|
||||
bar.Start("Convert Components");
|
||||
retVal = pNode->DoRecur( plMaxNode::ConvertComponents, fpErrorMsg, fSettings, &bar );
|
||||
}
|
||||
if(IOK())
|
||||
{
|
||||
// do this after convert
|
||||
bar.Start("Set Up Interface References");
|
||||
retVal = pNode->DoRecur( plMaxNode::MakeIfaceReferences, fpErrorMsg, fSettings, &bar );
|
||||
}
|
||||
|
||||
if(IOK() && fSettings->fDoPreshade)
|
||||
{
|
||||
// These need to be opened after the components have had a chance to flag the MaxNodes
|
||||
plLightMapGen::Instance().Open(fInterface, fInterface->GetTime(), fSettings->fDoLightMap);
|
||||
hsVertexShader::Instance().Open();
|
||||
|
||||
bar.Start("Preshade Geometry");
|
||||
retVal = pNode->DoRecur( plMaxNode::ShadeMesh, fpErrorMsg, fSettings, &bar );
|
||||
|
||||
plLightMapGen::Instance().Close();
|
||||
hsVertexShader::Instance().Close();
|
||||
}
|
||||
|
||||
if(IOK())
|
||||
{
|
||||
// Do this next-to-last--allows all the components to free up any temp data they kept around
|
||||
bar.Start("Component DeInit");
|
||||
retVal = pNode->DoRecur( plMaxNode::DeInitComponents, fpErrorMsg, fSettings, &bar );
|
||||
}
|
||||
if(IOK())
|
||||
{
|
||||
// Do this very last--it de-inits and frees all the maxNodeDatas lying around
|
||||
bar.Start("Clear MaxNodeDatas");
|
||||
retVal = pNode->DoAllRecur( plMaxNode::ClearMaxNodeData, fpErrorMsg, fSettings, &bar );
|
||||
}
|
||||
// fpErrorMsg->Set();
|
||||
|
||||
DeInit();
|
||||
|
||||
fInterface->SetIncludeXRefsInHierarchy(FALSE);
|
||||
|
||||
return IOK();
|
||||
}
|
||||
#ifndef HS_NO_TRY
|
||||
catch(plErrorMsg& err)
|
||||
{
|
||||
DeInit();
|
||||
fInterface->SetIncludeXRefsInHierarchy(FALSE);
|
||||
err.Show();
|
||||
return false;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
DeInit();
|
||||
fInterface->SetIncludeXRefsInHierarchy(FALSE);
|
||||
fpErrorMsg->Set(true, "plConvert", "Unknown error during convert\n");
|
||||
fpErrorMsg->Show();
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//#include "../MaxMain/plMaxNodeData.h"
|
||||
//#include <set>
|
||||
|
||||
hsBool ConvertList(hsTArray<plMaxNode*>& nodes, PMaxNodeFunc p, plErrorMsg *errMsg, plConvertSettings *settings)
|
||||
{
|
||||
for (int i = 0; i < nodes.Count(); i++)
|
||||
{
|
||||
(nodes[i]->*p)(errMsg, settings);
|
||||
|
||||
if (errMsg && errMsg->IsBogus())
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
hsBool plConvert::Convert(hsTArray<plMaxNode*>& nodes)
|
||||
{
|
||||
#ifndef HS_NO_TRY
|
||||
try
|
||||
#endif
|
||||
{
|
||||
fSettings->fReconvert = true;
|
||||
|
||||
hsBool retVal = true;
|
||||
|
||||
if (IOK())
|
||||
retVal = ConvertList(nodes, plMaxNode::ClearData, fpErrorMsg, fSettings);
|
||||
|
||||
if(IOK())
|
||||
retVal = ConvertList(nodes, plMaxNode::ConvertValidate, fpErrorMsg, fSettings);
|
||||
if(IOK())
|
||||
retVal = ConvertList(nodes, plMaxNode::SetupPropertiesPass, fpErrorMsg, fSettings);
|
||||
if(IOK())
|
||||
retVal = ConvertList(nodes, plMaxNode::PrepareSkin, fpErrorMsg, fSettings);
|
||||
if(IOK())
|
||||
retVal = ConvertList(nodes, plMaxNode::MakeSceneObject, fpErrorMsg, fSettings);
|
||||
if(IOK())
|
||||
retVal = ConvertList(nodes, plMaxNode::FirstComponentPass, fpErrorMsg, fSettings);
|
||||
if(IOK())
|
||||
retVal = ConvertList(nodes, plMaxNode::MakeController, fpErrorMsg,fSettings);
|
||||
if(IOK())
|
||||
retVal = ConvertList(nodes, plMaxNode::MakeCoordinateInterface, fpErrorMsg, fSettings);// must be before mesh
|
||||
if(IOK())
|
||||
retVal = ConvertList(nodes, plMaxNode::MakeParentOrRoomConnection, fpErrorMsg, fSettings); // after coord, before mesh (or any other pool data).
|
||||
|
||||
// These shouldn't be opened until the components have had a chance to flag the MaxNodes
|
||||
plLightMapGen::Instance().Open(fInterface, fInterface->GetTime(), fSettings->fDoLightMap);
|
||||
hsVertexShader::Instance().Open();
|
||||
|
||||
if(IOK())
|
||||
retVal = ConvertList(nodes, plMaxNode::MakeMesh, fpErrorMsg, fSettings); // must be before simulation
|
||||
|
||||
if(IOK()) // doesn't matter when
|
||||
retVal = ConvertList(nodes, plMaxNode::MakeLight, fpErrorMsg, fSettings);
|
||||
if(IOK()) // doesn't matter when
|
||||
retVal = ConvertList(nodes, plMaxNode::MakeOccluder, fpErrorMsg, fSettings);
|
||||
if(IOK()) // must be after mesh
|
||||
retVal = ConvertList(nodes, plMaxNode::MakeModifiers, fpErrorMsg, fSettings);
|
||||
if(IOK())
|
||||
retVal = ConvertList(nodes, plMaxNode::ConvertComponents, fpErrorMsg, fSettings);
|
||||
if(IOK())
|
||||
retVal = ConvertList(nodes, plMaxNode::ShadeMesh, fpErrorMsg, fSettings);
|
||||
|
||||
// These may be used by components, so don't close them till the end.
|
||||
plLightMapGen::Instance().Close();
|
||||
hsVertexShader::Instance().Close();
|
||||
|
||||
plgDispatch::MsgSend(new plTransformMsg(nil, nil, nil, nil));
|
||||
plgDispatch::MsgSend(new plDelayedTransformMsg(nil, nil, nil, nil));
|
||||
DeInit();
|
||||
|
||||
return IOK();
|
||||
}
|
||||
#ifndef HS_NO_TRY
|
||||
catch(plErrorMsg& err)
|
||||
{
|
||||
err.Show();
|
||||
return false;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
hsMessageBox("Unknown error during convert", "plConvert", hsMessageBoxNormal);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
hsBool plConvert::Init(Interface *ip, plErrorMsg* msg, plConvertSettings *settings)
|
||||
{
|
||||
fInterface = ip;
|
||||
fpErrorMsg = msg;
|
||||
fSettings = settings;
|
||||
|
||||
// Move us to time 0, so that things like initial transforms are always consistent with the 0th frame.
|
||||
// This saves our asses from things like the patch-generation process later
|
||||
ip->SetTime( 0, false );
|
||||
|
||||
hsConverterUtils::Instance().Init(true, fpErrorMsg);
|
||||
plBitmapCreator::Instance().Init(true, fpErrorMsg);
|
||||
hsMaterialConverter::Instance().Init(true, fpErrorMsg);
|
||||
hsControlConverter::Instance().Init(fpErrorMsg);
|
||||
plMeshConverter::Instance().Init(true, fpErrorMsg);
|
||||
plLayerConverter::Instance().Init(true, fpErrorMsg);
|
||||
|
||||
plGetLocationDlg::Instance().ResetDefaultLocation();
|
||||
|
||||
fQuit = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void plConvert::DeInit()
|
||||
{
|
||||
// Undo any autogenerated clusters.
|
||||
IAutoUnClusterRecur(fInterface->GetRootNode());
|
||||
|
||||
// clear out the message queue
|
||||
for (int i = 0; i < fMsgQueue.Count(); i++)
|
||||
plgDispatch::MsgSend(fMsgQueue[i]);
|
||||
|
||||
fMsgQueue.Reset();
|
||||
|
||||
hsControlConverter::Instance().DeInit();
|
||||
plMeshConverter::Instance().DeInit();
|
||||
plLayerConverter::Instance().DeInit();
|
||||
// Moving this to the end of writing the files out. Yes, this means that any unused mipmaps still get
|
||||
// written to disk, including ones loaded on preload, but it's the only way to get shared texture pages
|
||||
// to work without loading in the entire age worth of reffing objects. - 5.30.2002 mcn
|
||||
// plBitmapCreator::Instance().DeInit();
|
||||
|
||||
plNodeCleanupMsg *clean = TRACKED_NEW plNodeCleanupMsg();
|
||||
plgDispatch::MsgSend( clean );
|
||||
}
|
||||
|
||||
void plConvert::AddMessageToQueue(plMessage* msg)
|
||||
{
|
||||
fMsgQueue.Append(msg);
|
||||
}
|
||||
|
||||
void plConvert::SendEnvironmentMessage(plMaxNode* pNode, plMaxNode* efxRegion, plMessage* msg, hsBool ignorePhysicals )
|
||||
{
|
||||
for (int i = 0; i < pNode->NumberOfChildren(); i++)
|
||||
SendEnvironmentMessage((plMaxNode *)pNode->GetChildNode(i), efxRegion, msg, ignorePhysicals );
|
||||
|
||||
// don't call ourself...
|
||||
if (pNode == efxRegion)
|
||||
return;
|
||||
|
||||
// send the scene object this message:
|
||||
if (efxRegion->Contains( ((INode*)pNode)->GetNodeTM(hsConverterUtils::Instance().GetTime(pNode->GetInterface())).GetRow(3)) &&
|
||||
pNode->GetSceneObject() && ( !ignorePhysicals || !pNode->IsPhysical() ) )
|
||||
msg->AddReceiver( pNode->GetSceneObject()->GetKey() );
|
||||
}
|
||||
|
||||
plMaxNode* plConvert::GetRootNode()
|
||||
{
|
||||
return (plMaxNode *)fInterface->GetRootNode();
|
||||
}
|
||||
|
||||
BOOL plConvert::IAutoClusterRecur(INode* node)
|
||||
{
|
||||
plMaxNode* maxNode = (plMaxNode*)node;
|
||||
plComponentBase* comp = maxNode->ConvertToComponent();
|
||||
|
||||
if( comp && (comp->ClassID() == CLUSTER_COMP_CID) )
|
||||
{
|
||||
plClusterComponent* clust = (plClusterComponent*)comp;
|
||||
// Cluster decides if it needs autogen
|
||||
if( clust->AutoGen(fpErrorMsg) )
|
||||
return false;
|
||||
}
|
||||
int i;
|
||||
for( i = 0; i < node->NumberOfChildren(); i++ )
|
||||
{
|
||||
if( !IAutoClusterRecur(node->GetChildNode(i)) )
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOL plConvert::IAutoUnClusterRecur(INode* node)
|
||||
{
|
||||
plMaxNode* maxNode = (plMaxNode*)node;
|
||||
plComponentBase* comp = maxNode->ConvertToComponent();
|
||||
|
||||
if( comp && (comp->ClassID() == CLUSTER_COMP_CID) )
|
||||
{
|
||||
plClusterComponent* clust = (plClusterComponent*)comp;
|
||||
// Cluster remembers whether it was autogen'd.
|
||||
clust->AutoClear(fpErrorMsg);
|
||||
}
|
||||
int i;
|
||||
for( i = 0; i < node->NumberOfChildren(); i++ )
|
||||
{
|
||||
IAutoUnClusterRecur(node->GetChildNode(i));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool plConvert::IFindDuplicateNames()
|
||||
{
|
||||
INode *node = fInterface->GetRootNode();
|
||||
const char *name = ISearchNames(node, node);
|
||||
|
||||
if (!name)
|
||||
return false;
|
||||
|
||||
fpErrorMsg->Set(true,
|
||||
"Error in Conversion of Scene Objects",
|
||||
"Two objects in the scene share the name '%s'.\nUnique names are necessary during the export process.\n",
|
||||
name
|
||||
);
|
||||
fpErrorMsg->Show();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Recursivly search nodes for duplicate names, and return when one is found
|
||||
const char *plConvert::ISearchNames(INode *node, INode *root)
|
||||
{
|
||||
int count = ICountNameOccurances(root, node->GetName());
|
||||
if (count > 1)
|
||||
return node->GetName();
|
||||
|
||||
for (int i = 0; i < node->NumberOfChildren(); i++)
|
||||
{
|
||||
const char *name = ISearchNames(node->GetChildNode(i), root);
|
||||
if (name)
|
||||
return name;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Recursivly search nodes for this name, and return the number of times found
|
||||
int plConvert::ICountNameOccurances(INode *node, const char *name)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
if (!stricmp(name, node->GetName()))
|
||||
count++;
|
||||
|
||||
for (int i = 0; i < node->NumberOfChildren(); i++)
|
||||
count += ICountNameOccurances(node->GetChildNode(i), name);
|
||||
|
||||
return count;
|
||||
}
|
131
Sources/Tools/MaxConvert/plConvert.h
Normal file
131
Sources/Tools/MaxConvert/plConvert.h
Normal file
@ -0,0 +1,131 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#ifndef plConvert_inc
|
||||
#define plConvert_inc
|
||||
|
||||
#include "hsTypes.h"
|
||||
#include "hsTemplates.h"
|
||||
#include "../pnKeyedObject/plKey.h"
|
||||
|
||||
class plErrorMsg;
|
||||
class plLocation;
|
||||
class plMaxNode;
|
||||
class plMessage;
|
||||
class plLightMapGen;
|
||||
class hsVertexShader;
|
||||
|
||||
class plConvertSettings
|
||||
{
|
||||
public:
|
||||
plConvertSettings() : fSceneViewer(false), fReconvert(false), fDoPreshade(true), fDoLightMap(true),
|
||||
fLightMapGen(nil), fVertexShader(nil), fPhysicalsOnly(false), fExportPage(nil) {}
|
||||
|
||||
bool fSceneViewer; // Are we converting this for the SceneViewer?
|
||||
bool fReconvert; // Don't need to set, will be done internally by plConvert
|
||||
bool fDoPreshade; // Doesn't do preshading if false (flat shades)
|
||||
bool fDoLightMap; // Reuses available old lightmaps if false, else always generates fresh.
|
||||
bool fPhysicalsOnly;// Only solid physicals get meshes
|
||||
const char* fExportPage; // If this isn't nil, only export objects in this page
|
||||
|
||||
plLightMapGen* fLightMapGen;
|
||||
hsVertexShader* fVertexShader;
|
||||
};
|
||||
|
||||
class plConvert
|
||||
{
|
||||
protected:
|
||||
hsBool fQuit;
|
||||
plErrorMsg* fpErrorMsg;
|
||||
Interface* fInterface;
|
||||
plConvertSettings* fSettings;
|
||||
hsTArray<plMessage*> fMsgQueue;
|
||||
|
||||
plConvert();
|
||||
hsBool IMakeSceneObject(INode* node);
|
||||
plKey IGetRoomKey(INode* node);
|
||||
plKey INewRoom(INode* node, char roomName[]);
|
||||
hsBool IOK();
|
||||
|
||||
public:
|
||||
static plConvert& Instance();
|
||||
UInt32 fWarned;
|
||||
enum {
|
||||
kWarnedDecalOnBlendObj = 0x1,
|
||||
kWarnedBadMaterialOnParticle = 0x2,
|
||||
kWarnedBadParticle = 0x4,
|
||||
kWarnedDecalAndNonDecal = 0x8,
|
||||
kWarnedWrongProj = 0x10,
|
||||
kWarnedMissingProj = 0x20,
|
||||
kWarnedDecalOnNonDrawable = 0x40,
|
||||
kWarnedTooManyParticles = 0x80,
|
||||
kWarnedParticleVelAndOnePer = 0x100,
|
||||
kWarnedPhysics = 0x200,
|
||||
};
|
||||
|
||||
// Init the converter. Only good for one call of Convert.
|
||||
hsBool Init(Interface *ip, plErrorMsg* msg, plConvertSettings *settings);
|
||||
void DeInit();
|
||||
|
||||
hsBool Convert();
|
||||
hsBool Convert(hsTArray<plMaxNode*>& nodes); // Convert a set of nodes (for SceneViewer update)
|
||||
|
||||
plMaxNode* GetRootNode();
|
||||
void SendEnvironmentMessage(plMaxNode* pNode, plMaxNode* efxRegion, plMessage* msg, hsBool ignorePhysicals = false); // iterates through scene to find nodes contained by the efxRegion
|
||||
void AddMessageToQueue(plMessage* msg);
|
||||
|
||||
// Because components don't get the convert settings (too much work to retrofit all of them)
|
||||
plConvertSettings* GetConvertSettings() { return fSettings; }
|
||||
bool IsForSceneViewer() { return fSettings->fSceneViewer; }
|
||||
|
||||
// Search for nodes with the same name. Returns true if any are found and stops the export
|
||||
bool IFindDuplicateNames();
|
||||
// IFindDuplicateNames helper functions
|
||||
const char *ISearchNames(INode *node, INode *root);
|
||||
int ICountNameOccurances(INode *node, const char *name);
|
||||
// Does any pre-export generation necessary for distributors, then cleans up after export.
|
||||
BOOL IAutoClusterRecur(INode* node);
|
||||
BOOL IAutoUnClusterRecur(INode* node);
|
||||
};
|
||||
|
||||
|
||||
#endif // plSimpleConvert_inc
|
317
Sources/Tools/MaxConvert/plDistTree.cpp
Normal file
317
Sources/Tools/MaxConvert/plDistTree.cpp
Normal file
@ -0,0 +1,317 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#include "hsTypes.h"
|
||||
#include "Max.h"
|
||||
|
||||
|
||||
#include "plDistTree.h"
|
||||
|
||||
plDistTree::plDistTree()
|
||||
: fRoot(-1)
|
||||
{
|
||||
}
|
||||
|
||||
plDistTree::~plDistTree()
|
||||
{
|
||||
}
|
||||
|
||||
void plDistTree::Reset()
|
||||
{
|
||||
fRoot = -1;
|
||||
fNodes.Reset();
|
||||
}
|
||||
|
||||
void plDistTree::AddBoxIData(const Box3& box, const Box3& fade, UInt32 iData)
|
||||
{
|
||||
fRoot = IAddNodeRecur(fRoot, box, fade, iData);
|
||||
}
|
||||
|
||||
BOOL plDistTree::BoxClear(const Box3& box, const Box3& fade) const
|
||||
{
|
||||
return IBoxClearRecur(fRoot, box, fade);
|
||||
}
|
||||
|
||||
BOOL plDistTree::PointClear(const Point3& pt, const Box3& fade) const
|
||||
{
|
||||
return IPointClearRecur(fRoot, pt, fade);
|
||||
}
|
||||
|
||||
BOOL plDistTree::IFadesClear(const Box3& fade0, const Box3& fade1) const
|
||||
{
|
||||
// Only two ways fade can come out non-overlapping.
|
||||
// Either fade0 fades out before fade1 fades in, or v.v.
|
||||
|
||||
// First case, does fade0 fade out?
|
||||
if( fade0.Max()[2] > 0 )
|
||||
{
|
||||
// does fade1 fade in?
|
||||
if( fade1.Min()[2] < 0 )
|
||||
{
|
||||
// Okay they do, does fade0 fade out before fade1 fades in?
|
||||
if( fade0.Max()[0] <= fade1.Min()[0] )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Second case, same thing but reversed order
|
||||
if( fade1.Max()[2] > 0 )
|
||||
{
|
||||
// does fade0 fade in?
|
||||
if( fade0.Min()[2] < 0 )
|
||||
{
|
||||
// Okay they do, does fade1 fade out before fade0 fades in?
|
||||
if( fade1.Max()[0] <= fade0.Min()[0] )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOL plDistTree::IBox0ContainsBox1(const Box3& box0, const Box3& box1, const Box3& fade0, const Box3& fade1) const
|
||||
{
|
||||
#ifdef MAX_CONTAINS_WORKS
|
||||
if( !box0.Contains(box1) )
|
||||
return false;
|
||||
#else MAX_CONTAINS_WORKS
|
||||
if( (box0.Min()[0] > box1.Min()[0])
|
||||
||(box0.Min()[1] > box1.Min()[1])
|
||||
||(box0.Min()[2] > box1.Min()[2])
|
||||
||(box0.Max()[0] < box1.Max()[0])
|
||||
||(box0.Max()[1] < box1.Max()[1])
|
||||
||(box0.Max()[2] < box1.Max()[2]) )
|
||||
return false;
|
||||
#endif // MAX_CONTAINS_WORKS
|
||||
|
||||
if( IFadesClear(fade0, fade1) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOL plDistTree::IBoxesClear(const Box3& box0, const Box3& box1) const
|
||||
{
|
||||
return (box0.Min()[0] > box1.Max()[0])
|
||||
||(box0.Max()[0] < box1.Min()[0])
|
||||
|
||||
||(box0.Min()[1] > box1.Max()[1])
|
||||
||(box0.Max()[1] < box1.Min()[1])
|
||||
|
||||
||(box0.Min()[2] > box1.Max()[2])
|
||||
||(box0.Max()[2] < box1.Min()[2]);
|
||||
}
|
||||
|
||||
BOOL plDistTree::IBoxClearRecur(Int32 iNode, const Box3& box, const Box3& fade) const
|
||||
{
|
||||
if( iNode < 0 )
|
||||
return true;
|
||||
|
||||
if( IBoxesClear(fNodes[iNode].fBox, box) )
|
||||
return true;
|
||||
|
||||
if( IFadesClear(fNodes[iNode].fFade, fade) )
|
||||
return true;
|
||||
|
||||
if( fNodes[iNode].IsLeaf() )
|
||||
return false;
|
||||
|
||||
int i;
|
||||
for( i = 0; i < 8; i++ )
|
||||
{
|
||||
if( !IBoxClearRecur(fNodes[iNode].fChildren[i], box, fade) )
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOL plDistTree::IPointClearRecur(Int32 iNode, const Point3& pt, const Box3& fade) const
|
||||
{
|
||||
if( iNode < 0 )
|
||||
return true;
|
||||
|
||||
if( !fNodes[iNode].fBox.Contains(pt) )
|
||||
return true;
|
||||
|
||||
if( IFadesClear(fNodes[iNode].fFade, fade) )
|
||||
return true;
|
||||
|
||||
if( fNodes[iNode].IsLeaf() )
|
||||
return false;
|
||||
|
||||
int i;
|
||||
for( i = 0; i < 8; i++ )
|
||||
{
|
||||
if( !IPointClearRecur(fNodes[iNode].fChildren[i], pt, fade) )
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Int32 plDistTree::IAddNodeRecur(Int32 iNode, const Box3& box, const Box3& fade, UInt32 iData)
|
||||
{
|
||||
// if iNode < 0, make a node for box and return that.
|
||||
if( iNode < 0 )
|
||||
{
|
||||
return INextNode(box, fade, iData);
|
||||
}
|
||||
|
||||
// if the box is contained
|
||||
// if this node is a leaf, pitch the box
|
||||
//
|
||||
// else
|
||||
// recur on one of 8 children, based on
|
||||
// box's center relative to node center.
|
||||
|
||||
// if the box doesn't intercect this node,
|
||||
// replace this node with a node of combined boxes.
|
||||
// this node becomes sibling of box.
|
||||
|
||||
// if the box does intercect, but isn't contained
|
||||
// same thing.
|
||||
|
||||
|
||||
#if 0
|
||||
if( IBox0ContainsBox1(fNodes[iNode].fBox, box, fNodes[iNode].fFade, fade) )
|
||||
{
|
||||
if( !fNodes[iNode].IsLeaf() )
|
||||
#else
|
||||
if( !fNodes[iNode].IsLeaf() && IBox0ContainsBox1(fNodes[iNode].fBox, box, fNodes[iNode].fFade, fade) )
|
||||
{
|
||||
#endif
|
||||
{
|
||||
Int32 iChild = IGetChild(fNodes[iNode].fBox, box);
|
||||
|
||||
Int32 iChildNode = IAddNodeRecur(fNodes[iNode].fChildren[iChild], box, fade, iData);
|
||||
fNodes[iNode].fChildren[iChild] = iChildNode;
|
||||
|
||||
fNodes[iNode].fBox += fNodes[fNodes[iNode].fChildren[iChild]].fBox;
|
||||
}
|
||||
return iNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
return IMergeNodes(iNode, box, fade, iData);
|
||||
}
|
||||
}
|
||||
|
||||
Int32 plDistTree::IMergeNodes(Int32 iNode, const Box3& box, const Box3& fade, UInt32 iData)
|
||||
{
|
||||
Box3 parBox = box;
|
||||
parBox += fNodes[iNode].fBox;
|
||||
|
||||
Int32 pNode = INextNode(parBox, NonFade(), UInt32(-1));
|
||||
Int32 iChild = IGetChild(parBox, box);
|
||||
|
||||
Int32 cNode = INextNode(box, fade, iData);
|
||||
|
||||
fNodes[pNode].fChildren[iChild] = cNode;
|
||||
|
||||
// Put the original node in the opposite quadrant from the child.
|
||||
// This handles the case where one of the bounds completely contains
|
||||
// the other. The octant structure of the tree isn't relied on, it
|
||||
// only helps balance the tree. So being wrong here won't hurt anything.
|
||||
iChild = iChild ^ 0x7;
|
||||
|
||||
fNodes[pNode].fChildren[iChild] = iNode;
|
||||
|
||||
fNodes[pNode].SetIsLeaf(false);
|
||||
|
||||
return pNode;
|
||||
}
|
||||
|
||||
Int32 plDistTree::IGetChild(const Box3& parent, const Box3& child) const
|
||||
{
|
||||
Point3 parCenter = parent.Center();
|
||||
Point3 chiCenter = child.Center();
|
||||
|
||||
Int32 idx = ((parCenter[0] < chiCenter[0]) << 0)
|
||||
| ((parCenter[1] < chiCenter[1]) << 1)
|
||||
| ((parCenter[2] < chiCenter[2]) << 2);
|
||||
return idx;
|
||||
}
|
||||
|
||||
Int32 plDistTree::INextNode(const Box3& box, const Box3& fade, UInt32 iData)
|
||||
{
|
||||
Int32 iNode = fNodes.GetCount();
|
||||
|
||||
fNodes.Push();
|
||||
|
||||
fNodes[iNode].fFlags = plDistNode::kIsLeaf;
|
||||
fNodes[iNode].fBox = box;
|
||||
fNodes[iNode].fFade = fade;
|
||||
fNodes[iNode].fIData = iData;
|
||||
fNodes[iNode].fChildren[0]
|
||||
= fNodes[iNode].fChildren[1]
|
||||
= fNodes[iNode].fChildren[2]
|
||||
= fNodes[iNode].fChildren[3]
|
||||
= fNodes[iNode].fChildren[4]
|
||||
= fNodes[iNode].fChildren[5]
|
||||
= fNodes[iNode].fChildren[6]
|
||||
= fNodes[iNode].fChildren[7] = -1;
|
||||
|
||||
return iNode;
|
||||
}
|
||||
|
||||
void plDistTree::HarvestBox(const Box3& box, Tab<Int32>& out) const
|
||||
{
|
||||
IHarvestBoxRecur(fRoot, box, out);
|
||||
}
|
||||
|
||||
void plDistTree::IHarvestBoxRecur(Int32 iNode, const Box3& box, Tab<Int32>& out) const
|
||||
{
|
||||
if( iNode < 0 )
|
||||
return;
|
||||
|
||||
if( IBoxesClear(fNodes[iNode].fBox, box) )
|
||||
return;
|
||||
|
||||
if( fNodes[iNode].IsLeaf() )
|
||||
{
|
||||
out.Append(1, &iNode);
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
for( i = 0; i < 8; i++ )
|
||||
IHarvestBoxRecur(fNodes[iNode].fChildren[i], box, out);
|
||||
}
|
||||
}
|
119
Sources/Tools/MaxConvert/plDistTree.h
Normal file
119
Sources/Tools/MaxConvert/plDistTree.h
Normal file
@ -0,0 +1,119 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#ifndef plDistTree_inc
|
||||
#define plDistTree_inc
|
||||
|
||||
#include "hsTemplates.h"
|
||||
|
||||
class plDistNode
|
||||
{
|
||||
public:
|
||||
enum {
|
||||
kIsLeaf = 0x1
|
||||
};
|
||||
UInt32 fFlags;
|
||||
|
||||
Int32 fChildren[8];
|
||||
Box3 fBox;
|
||||
Box3 fFade;
|
||||
|
||||
union
|
||||
{
|
||||
void* fPData;
|
||||
UInt32 fIData;
|
||||
};
|
||||
|
||||
const Box3& GetBox() const { return fBox; }
|
||||
|
||||
BOOL IsLeaf() const { return 0 != (fFlags & kIsLeaf); }
|
||||
void SetIsLeaf(BOOL on) { if(on)fFlags |= kIsLeaf; else fFlags &= ~kIsLeaf; }
|
||||
};
|
||||
|
||||
class plDistTree
|
||||
{
|
||||
protected:
|
||||
|
||||
Int32 fRoot;
|
||||
|
||||
hsLargeArray<plDistNode> fNodes;
|
||||
|
||||
Int32 IAddNodeRecur(Int32 iNode, const Box3& box, const Box3& fade, UInt32 iData);
|
||||
|
||||
Int32 IMergeNodes(Int32 iNode, const Box3& box, const Box3& fade, UInt32 iData);
|
||||
Int32 INextNode(const Box3& box, const Box3& fade, UInt32 iData);
|
||||
|
||||
Int32 IGetChild(const Box3& parent, const Box3& child) const;
|
||||
|
||||
inline BOOL IBoxesClear(const Box3& box0, const Box3& box1) const;
|
||||
inline BOOL IFadesClear(const Box3& fade0, const Box3& fade1) const;
|
||||
|
||||
BOOL IBox0ContainsBox1(const Box3& box0, const Box3& box1, const Box3& fade0, const Box3& fade1) const;
|
||||
|
||||
BOOL IBoxClearRecur(Int32 iNode, const Box3& box, const Box3& fade) const;
|
||||
BOOL IPointClearRecur(Int32 iNode, const Point3& pt, const Box3& fade) const;
|
||||
|
||||
void IHarvestBoxRecur(Int32 iNode, const Box3& box, Tab<Int32>& out) const;
|
||||
|
||||
public:
|
||||
plDistTree();
|
||||
virtual ~plDistTree();
|
||||
|
||||
void Reset();
|
||||
|
||||
void AddBoxPData(const Box3& box, const Box3& fade, void* pData=nil) { AddBoxIData(box, fade, UInt32(pData)); }
|
||||
void AddBoxIData(const Box3& box, const Box3& fade, UInt32 iData=0);
|
||||
void AddBox(const Box3& box, const Box3& fade=NonFade()) { AddBoxIData(box, fade, 0); }
|
||||
|
||||
BOOL BoxClear(const Box3& box, const Box3& fade) const;
|
||||
BOOL PointClear(const Point3& pt, const Box3& fade) const;
|
||||
|
||||
BOOL IsEmpty() const { return fRoot < 0; }
|
||||
|
||||
static Box3 NonFade() { return Box3(Point3(0,0,0), Point3(0,0,0)); }
|
||||
|
||||
void HarvestBox(const Box3& box, Tab<Int32>& out) const;
|
||||
|
||||
const plDistNode& GetBox(Int32 i) const { return fNodes[i]; }
|
||||
};
|
||||
|
||||
#endif // plDistTree_inc
|
1483
Sources/Tools/MaxConvert/plDistributor.cpp
Normal file
1483
Sources/Tools/MaxConvert/plDistributor.cpp
Normal file
File diff suppressed because it is too large
Load Diff
421
Sources/Tools/MaxConvert/plDistributor.h
Normal file
421
Sources/Tools/MaxConvert/plDistributor.h
Normal file
@ -0,0 +1,421 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#ifndef plDistributor_inc
|
||||
#define plDistributor_inc
|
||||
|
||||
#include "../plMath/plRandom.h"
|
||||
#include "plDistTree.h"
|
||||
|
||||
class INode;
|
||||
class Mesh;
|
||||
class TriObject;
|
||||
|
||||
class BitmapTex;
|
||||
class plLayerTex;
|
||||
class plExportProgressBar;
|
||||
class plMaxNode;
|
||||
class plDistTree;
|
||||
|
||||
// To Use:
|
||||
//
|
||||
// First you must set the interface
|
||||
// Second, you must set the node(s) to be replicated.
|
||||
// If multiple replicants, they will be randomly selected at each plant site.
|
||||
// Set the spacing. Default is 10 or so, but shouldn't be counted on.
|
||||
// Set the spacing range. Set it to less than half the spacing to prevent
|
||||
// replicants piling up on each other.
|
||||
// Rather than increasing the spacing range (which causes pileup), you can increase
|
||||
// the randomness of placement with the overall probability factor. Reducing it
|
||||
// means fewer grid points will be used, so placement seems more random
|
||||
//
|
||||
// Options:
|
||||
// PolarRange - defines the cone about the surface normal to randomly fill for up direction
|
||||
// PolarBunch - defines tendency to bunch around the center of PolarRange cone,
|
||||
// with zero being uniform distribution, and one being all on cone axis.
|
||||
// AlignmentVector - defines a world space preferred up orientation.
|
||||
// AlignmentWeight - blend factor between random normal (from polar stuff) and
|
||||
// above AlignmentVector.
|
||||
// ScaleRange - defines range of non-uniform scale to apply to each replicant.
|
||||
// ProbabilityTexmap - A BitmapTex which maps the probability of an instance
|
||||
// taking root at any point on the surface. Various interpretations of the
|
||||
// map available (see ProbabilityChan). If the surface mesh doesn't have
|
||||
// the appropriate uvw mapping for the map, the map will be ignored.
|
||||
// ProbabilityChan - defines interpretation of texel value from ProbTexmap
|
||||
// into a probability. ColorChan enum types are pretty self-explanatory.
|
||||
// In all cases, a higher texel channel value means more likely of a
|
||||
// replicant taking root there.
|
||||
//
|
||||
// Finally, call Distrubute() with a node containing a surface to be populated.
|
||||
//
|
||||
// Modifying. Were actually creating the new node instances, but then we just
|
||||
// want to re-pack them into clusters anyway. So all we really need is to
|
||||
// know which template (fRepNodes) and what transform to use for it. We can
|
||||
// use that to make our clusters, without bogging Max down with adding and
|
||||
// deleting a gazillion INodes.
|
||||
|
||||
class plDistribInstance
|
||||
{
|
||||
public:
|
||||
INode* fNode;
|
||||
Matrix3 fNodeTM;
|
||||
Matrix3 fObjectTM;
|
||||
|
||||
INode* fBone;
|
||||
BOOL fRigid;
|
||||
|
||||
Box3 fFade;
|
||||
|
||||
Point3 fFlex;
|
||||
|
||||
Mesh* fMesh;
|
||||
};
|
||||
|
||||
class plDistribInstTab : public Tab<plDistribInstance>
|
||||
{
|
||||
};
|
||||
|
||||
class plMeshCache
|
||||
{
|
||||
public:
|
||||
Mesh* fMesh;
|
||||
Point3 fFlex;
|
||||
|
||||
plMeshCache() {}
|
||||
};
|
||||
|
||||
class plMeshCacheTab : public Tab<plMeshCache>
|
||||
{
|
||||
};
|
||||
|
||||
class plDistributor
|
||||
{
|
||||
public:
|
||||
enum ColorChan
|
||||
{
|
||||
kRed = 0x1,
|
||||
kGreen = 0x2,
|
||||
kBlue = 0x4,
|
||||
kAlpha = 0x8,
|
||||
kAverageRedGreen = kRed | kGreen,
|
||||
kAverageRedGreenTimesAlpha = kRed | kGreen | kAlpha,
|
||||
kAverage = kRed | kGreen | kBlue,
|
||||
kAverageTimesAlpha = kAverage | kAlpha,
|
||||
kMax = 0x100,
|
||||
kMaxColor = kMax | kRed | kGreen | kBlue,
|
||||
kMaxColorTimesAlpha = kMaxColor | kAlpha,
|
||||
kMaxRedGreen = kMax | kRed | kGreen,
|
||||
kMaxRedGreenTimesAlpha = kMaxRedGreen | kAlpha
|
||||
};
|
||||
enum
|
||||
{
|
||||
kLockNone = 0x0,
|
||||
kLockX = 0x1,
|
||||
kLockY = 0x2,
|
||||
kLockZ = 0x4
|
||||
};
|
||||
enum
|
||||
{
|
||||
kWgtMapChan = 66,
|
||||
kNormMapChan = 67
|
||||
};
|
||||
enum IsoType
|
||||
{
|
||||
kIsoNone,
|
||||
kIsoLow,
|
||||
kIsoMedium,
|
||||
kIsoHigh,
|
||||
|
||||
kIsoMax = kIsoHigh
|
||||
};
|
||||
enum ConformType
|
||||
{
|
||||
kConformNone,
|
||||
kConformAll,
|
||||
kConformHeight,
|
||||
kConformCheck,
|
||||
kConformBase
|
||||
};
|
||||
protected:
|
||||
mutable INode* fSurfNode;
|
||||
mutable Mesh* fSurfMesh;
|
||||
mutable TriObject* fSurfObjToDelete;
|
||||
|
||||
mutable INodeTab fRepNodes;
|
||||
|
||||
mutable plDistTree* fDistTree;
|
||||
mutable plDistTree fMeshTree;
|
||||
|
||||
Interface* fInterface;
|
||||
|
||||
IsoType fIsolation;
|
||||
ConformType fConformity;
|
||||
BOOL fFaceNormals;
|
||||
|
||||
float fSpacing;
|
||||
float fRndPosRadius;
|
||||
|
||||
Point3 fAlignVec;
|
||||
float fAlignWgt;
|
||||
|
||||
float fOffsetMin;
|
||||
float fOffsetMax;
|
||||
|
||||
Point3 fAngProbVec;
|
||||
float fAngProbLo;
|
||||
float fAngProbHi;
|
||||
float fAngProbTrans;
|
||||
|
||||
float fAltProbLo;
|
||||
float fAltProbHi;
|
||||
float fAltProbTrans;
|
||||
|
||||
float fPolarRange;
|
||||
float fTanPolarRange;
|
||||
float fAzimuthRange;
|
||||
|
||||
float fOverallProb;
|
||||
|
||||
float fPolarBunch;
|
||||
|
||||
ULONG fScaleLock;
|
||||
Point3 fScaleLo;
|
||||
Point3 fScaleHi;
|
||||
|
||||
BitmapTex* fProbBitmapTex;
|
||||
plLayerTex* fProbLayerTex;
|
||||
ColorChan fProbColorChan;
|
||||
|
||||
float fProbRemapFromLo;
|
||||
float fProbRemapFromHi;
|
||||
float fProbRemapToLo;
|
||||
float fProbRemapToHi;
|
||||
|
||||
float fMaxConform; // in feet
|
||||
|
||||
Box3 fFade;
|
||||
INode* fBone;
|
||||
BOOL fRigid;
|
||||
|
||||
// Temps used during processing.
|
||||
mutable Matrix3 fSurfToWorld;
|
||||
mutable Matrix3 fWorldToSurf;
|
||||
mutable Matrix3 fSurfToWorldVec;
|
||||
mutable Matrix3 fWorldToSurfVec;
|
||||
mutable Point3 fSurfAlignVec;
|
||||
mutable Point3 fSurfAngProbVec;
|
||||
mutable plRandom fRand;
|
||||
mutable float fCosAngProbHi;
|
||||
mutable float fCosAngProbHiTrans;
|
||||
mutable float fCosAngProbLo;
|
||||
mutable float fCosAngProbLoTrans;
|
||||
|
||||
void ISetAngProbCosines() const;
|
||||
BOOL ISetSurfaceNode(INode* node) const;
|
||||
BOOL IGetMesh(INode* node, TriObject*& objToDelete, Mesh*& retMesh) const;
|
||||
|
||||
BOOL INeedMeshTree() const;
|
||||
void IMakeMeshTree() const;
|
||||
void IFindFaceSet(const Box3& box, Tab<Int32>& faces) const;
|
||||
BOOL IProjectVertex(const Point3& pt, const Point3& dir, float maxDist, Tab<Int32>&faces, Point3& projPt) const;
|
||||
BOOL IConform(Matrix3& l2w, int iRepNode, plMeshCacheTab& cache, int& iCache) const;
|
||||
BOOL IConformHeight(Matrix3& l2w, int iRepNode, plMeshCacheTab& cache, int& iCache) const;
|
||||
BOOL IConformAll(Matrix3& l2w, int iRepNode, plMeshCacheTab& cache, int& iCache) const;
|
||||
BOOL IConformCheck(Matrix3& l2w, int iRepNode, plMeshCacheTab& cache, int& iCache) const;
|
||||
BOOL IConformBase(Matrix3& l2w, int iRepNode, plMeshCacheTab& cache, int& iCache) const;
|
||||
|
||||
Matrix3 IOTM(int iRepNode) const;
|
||||
Matrix3 IInvOTM(int iRepNode) const;
|
||||
|
||||
Matrix3 IGenerateTransform(int iRepNode, int iFace, const Point3& pt, const Point3& bary) const;
|
||||
hsBool IProbablyDoIt(int iFace, Point3& del, const Point3& bary) const;
|
||||
hsBool IFailsAltProb(int iFace, const Point3& bary) const;
|
||||
hsBool IFailsAngProb(int iFace, const Point3& bary) const;
|
||||
hsBool IFailsProbBitmap(int iFace, const Point3& bary) const;
|
||||
Box3 ISetupGrid(const Point3& p0, const Point3& p1, const Point3& p2) const;
|
||||
Point3& IPerturbPoint(Point3& pt) const;
|
||||
int ISelectRepNode() const;
|
||||
Point3 IPerpAxis(const Point3& p) const;
|
||||
Point3 IGetSurfaceNormal(int iFace, const Point3& bary) const;
|
||||
|
||||
BOOL ISpaceClear(int iRepNode, const Matrix3& l2w, Box3& clearBox, plMeshCacheTab& cache) const;
|
||||
void IReserveSpace(const Box3& clearBox) const;
|
||||
|
||||
void IReplicate(Matrix3& l2w, int iRep, plDistribInstTab& reps, plMeshCache& mCache) const;
|
||||
void IDistributeOverFace(int iFace, plDistribInstTab& reps, plMeshCacheTab& cache) const;
|
||||
BOOL IDistributeOverMesh(plDistribInstTab& reps, plMeshCacheTab& cache, plExportProgressBar& bar) const;
|
||||
|
||||
void IClear();
|
||||
BOOL IValidateSettings(INode* surfNode, plMeshCacheTab& cache) const;
|
||||
|
||||
BOOL ISetupNormals(plMaxNode* node, Mesh* mesh, BOOL radiateNorm) const;
|
||||
BOOL IDuplicate2Sided(plMaxNode* node, Mesh* mesh) const;
|
||||
BOOL ISetupSkinWeights(plMaxNode* node, Mesh* mesh, const Point3& flex) const;
|
||||
BOOL IReadyRepNodes(plMeshCacheTab& cache) const;
|
||||
public:
|
||||
|
||||
plDistributor();
|
||||
virtual ~plDistributor();
|
||||
|
||||
void SetTheInterface(Interface* i) { fInterface = i; }
|
||||
Interface* GetTheInterface() const { return fInterface; }
|
||||
|
||||
BOOL Distribute(INode* surfNode, plDistribInstTab& replicants, plMeshCacheTab& cache, plExportProgressBar& bar) const;
|
||||
|
||||
void Reset();
|
||||
UInt32 GetRandSeed() const;
|
||||
void SetRandSeed(int seed);
|
||||
|
||||
void ClearReplicateNodes();
|
||||
void AddReplicateNode(INode* node);
|
||||
int GetNumReplicateNodes() const { return fRepNodes.Count(); }
|
||||
INode* GetReplicateNode(int i) const { return fRepNodes[i]; }
|
||||
|
||||
INode* GetSurfaceNode() const { return fSurfNode; }
|
||||
|
||||
void SetSpacing(float f) { fSpacing = f; }
|
||||
float GetSpacing() const { return fSpacing; }
|
||||
|
||||
void SetSpacingRange(float f) { fRndPosRadius = f; }
|
||||
float GetSpacingRange() const { return fRndPosRadius; }
|
||||
|
||||
void SetAlignmentVec(const Point3& v) { fAlignVec = v; }
|
||||
Point3 GetAlignmentVec() const { return fAlignVec; }
|
||||
|
||||
void SetAlignmentWeight(float w) { fAlignWgt = w / 100.f; }
|
||||
float GetAlignmentWeight() const { return fAlignWgt * 100.f; }
|
||||
|
||||
void SetPolarRange(float deg);
|
||||
float GetPolarRange() const { return hsScalarRadToDeg(fPolarRange); }
|
||||
|
||||
void SetAzimuthRange(float deg) { fAzimuthRange = hsScalarDegToRad(deg); }
|
||||
float GetAzimuthRange() const { return hsScalarRadToDeg(fAzimuthRange); }
|
||||
|
||||
void SetOverallProb(float percent) { fOverallProb = percent/100.f; }
|
||||
float GetOverallProb() const { return fOverallProb * 100.f; }
|
||||
|
||||
void SetAngleProbVec(const Point3& v) { fAngProbVec = v; }
|
||||
Point3 GetAngleProbVec() const { return fAngProbVec; }
|
||||
|
||||
void SetAngleProbHi(float deg) { fAngProbHi = deg; }
|
||||
float GetAngleProbHi() const { return fAngProbHi; }
|
||||
|
||||
void SetAngleProbLo(float deg) { fAngProbLo = deg; }
|
||||
float GetAngleProbLo() const { return fAngProbLo; }
|
||||
|
||||
void SetAngleProbTransition(float deg) { fAngProbTrans = deg; }
|
||||
float GetAngleProbTransition() const { return fAngProbTrans; }
|
||||
|
||||
void SetMinAltitude(float feet) { fAltProbLo = feet; }
|
||||
float GetMinAltitude() const { return fAltProbLo; }
|
||||
|
||||
void SetMaxAltitude(float feet) { fAltProbHi = feet; }
|
||||
float GetMaxAltitude() const { return fAltProbHi; }
|
||||
|
||||
void SetAltitudeTransition(float feet) { fAltProbTrans = feet; }
|
||||
float GetAltitudeTransition() const { return fAltProbTrans; }
|
||||
|
||||
void SetPolarBunch(float b) { fPolarBunch = b/100.f; }
|
||||
float GetPolarBunch() const { return fPolarBunch * 100.f; }
|
||||
|
||||
void SetScaleRange(const Point3& lo, const Point3& hi) { fScaleLo = lo; fScaleHi = hi; }
|
||||
Point3 GetScaleRangeMin() const { return fScaleLo; }
|
||||
Point3 GetScaleRangeMax() const { return fScaleHi; }
|
||||
|
||||
void SetProbabilityBitmapTex(BitmapTex* t);
|
||||
BitmapTex* GetProbabilityBitmapTex() const { return fProbBitmapTex; }
|
||||
|
||||
void SetProbabilityLayerTex(plLayerTex* t);
|
||||
plLayerTex* GetProbabilityLayerTex() const { return fProbLayerTex; }
|
||||
|
||||
void SetProbabilityChan(ColorChan c) { fProbColorChan = c; }
|
||||
ColorChan GetProbabilityChan() const { return fProbColorChan; }
|
||||
|
||||
void SetProbabilityRemapFromLo(float f) { fProbRemapFromLo = f / 255.f; }
|
||||
float GetProbabilityRemapFromLo() const { return fProbRemapFromLo * 255.f; }
|
||||
|
||||
void SetProbabilityRemapFromHi(float f) { fProbRemapFromHi = f / 255.f; }
|
||||
float GetProbabilityRemapFromHi() const { return fProbRemapFromHi * 255.f; }
|
||||
|
||||
void SetProbabilityRemapToLo(float f) { fProbRemapToLo = f / 255.f; }
|
||||
float GetProbabilityRemapToLo() const { return fProbRemapToLo * 255.f; }
|
||||
|
||||
void SetProbabilityRemapToHi(float f) { fProbRemapToHi = f / 255.f; }
|
||||
float GetProbabilityRemapToHi() const { return fProbRemapToHi * 255.f; }
|
||||
|
||||
// We don't really know what fades are, they're just something we're handed that
|
||||
// we stamp on every distribInstance we generate. See plDistribComponent.h.
|
||||
void SetFade(const Box3& fade) { fFade = fade; }
|
||||
Box3 GetFade() const { return fFade; }
|
||||
|
||||
void SetBone(INode* b) { fBone = b; }
|
||||
INode* GetBone() const { return fBone; }
|
||||
|
||||
void SetRigid(BOOL b) { fRigid = b; }
|
||||
BOOL GetRigid() const { return fRigid; }
|
||||
|
||||
void SetScaleLock(ULONG f) { fScaleLock = f; }
|
||||
ULONG GetScaleLock() const { return fScaleLock; }
|
||||
|
||||
void SetDistTree(plDistTree* dt) { fDistTree = dt; }
|
||||
plDistTree* GetDistTree() const { return fDistTree; }
|
||||
|
||||
void SetIsolation(IsoType t) { fIsolation = t; }
|
||||
IsoType GetIsolation() const { return fIsolation; }
|
||||
|
||||
void SetConformity(ConformType t) { fConformity = t; }
|
||||
ConformType GetConformity() const { return fConformity; }
|
||||
|
||||
void SetMaxConform(float feet) { fMaxConform = feet; }
|
||||
float GetMaxConform() const { return fMaxConform; }
|
||||
|
||||
void SetMinOffset(float feet) { fOffsetMin = feet; }
|
||||
float GetMinOffset() const { return fOffsetMin; }
|
||||
|
||||
void SetMaxOffset(float feet) { fOffsetMax = feet; }
|
||||
float GetMaxOffset() const { return fOffsetMax; }
|
||||
|
||||
void SetFaceNormals(BOOL on=true) { fFaceNormals = on; }
|
||||
BOOL GetFaceNormals() const { return fFaceNormals; }
|
||||
};
|
||||
|
||||
#endif // plDistributor_inc
|
1136
Sources/Tools/MaxConvert/plLayerConverter.cpp
Normal file
1136
Sources/Tools/MaxConvert/plLayerConverter.cpp
Normal file
File diff suppressed because it is too large
Load Diff
139
Sources/Tools/MaxConvert/plLayerConverter.h
Normal file
139
Sources/Tools/MaxConvert/plLayerConverter.h
Normal file
@ -0,0 +1,139 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plLayerConverter - Utility class that converts plPlasmaMAXLayers into //
|
||||
// other stuff. //
|
||||
// //
|
||||
//// Version History //////////////////////////////////////////////////////////
|
||||
// //
|
||||
// 1.13.2002 mcn - Created. //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _plLayerConverter_h
|
||||
#define _plLayerConverter_h
|
||||
|
||||
#include "hsTypes.h"
|
||||
#include "hsTemplates.h"
|
||||
#include "Max.h"
|
||||
|
||||
|
||||
//// Class Definition /////////////////////////////////////////////////////////
|
||||
|
||||
class plErrorMsg;
|
||||
class plLayerInterface;
|
||||
class plMaxNode;
|
||||
class plPlasmaMAXLayer;
|
||||
class plLayer;
|
||||
class plLocation;
|
||||
class plBitmapData;
|
||||
class plDynamicTextMap;
|
||||
class plBitmap;
|
||||
class plCubicRenderTarget;
|
||||
class hsConverterUtils;
|
||||
class plDynamicTextLayer;
|
||||
|
||||
class plLayerConverter
|
||||
{
|
||||
private:
|
||||
|
||||
plLayerConverter();
|
||||
|
||||
protected:
|
||||
|
||||
static const Class_ID fDerivedTypes[];
|
||||
|
||||
public:
|
||||
|
||||
~plLayerConverter();
|
||||
static plLayerConverter &Instance( void );
|
||||
|
||||
void Init( hsBool save, plErrorMsg *msg );
|
||||
void DeInit( void );
|
||||
|
||||
plLayerInterface *ConvertTexmap( Texmap *texmap, plMaxNode *maxNode,
|
||||
UInt32 blendFlags, hsBool preserveUVOffset, hsBool upperLayer );
|
||||
plBitmap *CreateSimpleTexture(const char *fileName, const plLocation &loc, UInt32 clipID = 0, UInt32 texFlags = 0, bool useJPEG = false);
|
||||
|
||||
void MuteWarnings( void );
|
||||
void UnmuteWarnings( void );
|
||||
|
||||
protected:
|
||||
|
||||
plErrorMsg *fErrorMsg;
|
||||
UInt32 fWarned, fSavedWarned;
|
||||
hsBool fSaving;
|
||||
|
||||
Interface *fInterface;
|
||||
hsConverterUtils &fConverterUtils;
|
||||
|
||||
const char *fDbgNodeName;
|
||||
|
||||
hsTArray<plPlasmaMAXLayer *> fConvertedLayers;
|
||||
|
||||
|
||||
plLayer *ICreateLayer( const char *name, hsBool upperLayer, plLocation &loc );
|
||||
void IProcessUVGen( plPlasmaMAXLayer *srcLayer, plLayer *destLayer, plBitmapData *bitmapData, hsBool preserveUVOffset );
|
||||
plDynamicTextMap *ICreateDynTextMap( const char *layerName, UInt32 width, UInt32 height, hsBool includeAlpha, plMaxNode *node );
|
||||
|
||||
plLayer *IAssignTexture( plBitmapData *bd, plMaxNode *maxNode, plLayer *destLayer, hsBool upperLayer, int clipID = -1 );
|
||||
plCubicRenderTarget *IMakeCubicRenderTarget( const char *name, plMaxNode *maxNode, plMaxNode *anchor );
|
||||
|
||||
// Add your function to process your layer type here
|
||||
plLayerInterface *IConvertLayerTex( plPlasmaMAXLayer *layer, plMaxNode *maxNode, UInt32 blendFlags, hsBool preserveUVOffset, hsBool upperLayer );
|
||||
plLayerInterface *IConvertStaticEnvLayer( plPlasmaMAXLayer *layer, plMaxNode *maxNode, UInt32 blendFlags, hsBool preserveUVOffset, hsBool upperLayer );
|
||||
plLayerInterface *IConvertDynamicEnvLayer( plPlasmaMAXLayer *layer, plMaxNode *maxNode, UInt32 blendFlags, hsBool preserveUVOffset, hsBool upperLayer );
|
||||
plLayerInterface *IConvertCameraLayer( plPlasmaMAXLayer *layer, plMaxNode *maxNode, UInt32 blendFlags, hsBool preserveUVOffset, hsBool upperLayer );
|
||||
plLayerInterface *IConvertDynamicTextLayer( plPlasmaMAXLayer *layer, plMaxNode *maxNode, UInt32 blendFlags, hsBool preserveUVOffset, hsBool upperLayer );
|
||||
|
||||
plBitmap* IGetAttenRamp( plMaxNode *maxNode, BOOL isAdd, int loClamp, int hiClamp);
|
||||
plLayer* ICreateAttenuationLayer(const char* name, plMaxNode *maxNode, int uvwSrc, float tr0, float op0, float tr1, float op1, int loClamp, int hiClamp);
|
||||
plLayerInterface* IConvertAngleAttenLayer(plPlasmaMAXLayer *layer, plMaxNode *maxNode, UInt32 blendFlags, hsBool preserveUVOffset, hsBool upperLayer);
|
||||
|
||||
void IRegisterConversion( plPlasmaMAXLayer *origLayer, plLayerInterface *convertedLayer );
|
||||
|
||||
UInt32 *IGetInitBitmapBuffer( plDynamicTextLayer *layer ) const;
|
||||
|
||||
};
|
||||
|
||||
#endif // _plLayerConverter_h
|
1630
Sources/Tools/MaxConvert/plLightMapGen.cpp
Normal file
1630
Sources/Tools/MaxConvert/plLightMapGen.cpp
Normal file
File diff suppressed because it is too large
Load Diff
190
Sources/Tools/MaxConvert/plLightMapGen.h
Normal file
190
Sources/Tools/MaxConvert/plLightMapGen.h
Normal file
@ -0,0 +1,190 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#ifndef plLightMapGen_inc
|
||||
#define plLightMapGen_inc
|
||||
|
||||
#include "hsTemplates.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class plMaxLightContext;
|
||||
class plRenderGlobalContext;
|
||||
class plLayerInterface;
|
||||
class plMaxNode;
|
||||
class hsGMaterial;
|
||||
class plGeometrySpan;
|
||||
class plMipmap;
|
||||
class plBitmap;
|
||||
struct hsColorRGBA;
|
||||
struct hsPoint3;
|
||||
struct hsVector3;
|
||||
struct hsMatrix44;
|
||||
class plErrorMsg;
|
||||
class plConvertSettings;
|
||||
class hsBounds3Ext;
|
||||
class plLightMapComponent;
|
||||
|
||||
class plLightMapInfo
|
||||
{
|
||||
public:
|
||||
ObjLightDesc* fObjLiDesc;
|
||||
INode* fLiNode;
|
||||
int fResetShadowType;
|
||||
float fResetMapRange;
|
||||
float fMapRange;
|
||||
hsBool fNewRender;
|
||||
};
|
||||
|
||||
class plLightMapGen
|
||||
{
|
||||
protected:
|
||||
Interface* fInterface;
|
||||
TimeValue fTime;
|
||||
|
||||
int fUVWSrc;
|
||||
float fScale;
|
||||
|
||||
float fMapRange;
|
||||
|
||||
int fWidth;
|
||||
int fHeight;
|
||||
|
||||
bool fRecalcLightMaps;
|
||||
|
||||
Renderer* fRenderer;
|
||||
#ifdef MF_NEW_RGC
|
||||
RenderGlobalContext* fRGC;
|
||||
#else // MF_NEW_RGC
|
||||
plRenderGlobalContext* fRGC;
|
||||
#endif // MF_NEW_RGC
|
||||
RendParams* fRP;
|
||||
|
||||
hsTArray<plLightMapInfo> fAllLights;
|
||||
hsTArray<plLightMapInfo*> fActiveLights;
|
||||
|
||||
mutable hsTArray<plLayerInterface*> fCreatedLayers;
|
||||
mutable hsTArray<plMipmap*> fPreppedMipmaps;
|
||||
|
||||
mutable hsTArray<plBitmap*> fNewMaps; // Mipmaps created this session (not loaded from disk)
|
||||
|
||||
std::vector<plLightMapComponent*> fSharedComponents; // HACK so we can get rid of key refs before deleting bitmaps
|
||||
|
||||
hsBounds3Ext IGetBoundsLightSpace(INode* node, INode* liNode);
|
||||
hsBool IDirAffectsNode(plLightMapInfo* liInfo, LightObject* liObj, INode* node);
|
||||
hsBool ISpotAffectsNode(plLightMapInfo* liInfo, LightObject* liObj, INode* node);
|
||||
hsBool IOmniAffectsNode(plLightMapInfo* liInfo, LightObject* liObj, INode* node);
|
||||
hsBool ILightAffectsNode(plLightMapInfo* liInfo, LightObject* liObj, INode* node);
|
||||
|
||||
hsBool IPrepLight(plLightMapInfo* liInfo, INode* node);
|
||||
hsBool IGetLight(INode* node);
|
||||
hsBool IFindLightsRecur(INode* node);
|
||||
hsBool IFindActiveLights(plMaxNode* node);
|
||||
hsBool IReleaseActiveLights();
|
||||
hsBool IReleaseAllLights();
|
||||
|
||||
int IPowerOfTwo(int sz) const;
|
||||
hsBool ISelectBitmapDimension(plMaxNode* node, const hsMatrix44& l2w, const hsMatrix44& w2l, hsTArray<plGeometrySpan *> &spans);
|
||||
hsBool ICompressLightMaps();
|
||||
|
||||
hsBool IsFresh(plBitmap* map) const;
|
||||
|
||||
hsBool IAddToLightMap(plLayerInterface* lay, plMipmap* src) const;
|
||||
plMipmap* IMakeAccumBitmap(plLayerInterface* lay) const;
|
||||
void IInitBitmapColor(plMipmap* bitmap, const hsColorRGBA& col) const;
|
||||
plLayerInterface* IGetLightMapLayer(plMaxNode* node, plGeometrySpan& span);
|
||||
plLayerInterface* IMakeLightMapLayer(plMaxNode* node, plGeometrySpan& span);
|
||||
int IGetUVWSrc() const { return fUVWSrc; }
|
||||
|
||||
UInt32 IShadePoint(plMaxLightContext& ctx, const Color& amb, const hsPoint3& p, const hsVector3& n);
|
||||
hsBool IShadeVerts(plMaxLightContext& ctx, const Color& amb, const hsPoint3 pt[3], const hsVector3 norm[3], const hsPoint3 uv[3], plMipmap* bitmap);
|
||||
hsBool IShadeFace(plMaxNode* node, const hsMatrix44& l2w, const hsMatrix44& w2l, plGeometrySpan& span, int iFace, plMipmap* bitmap);
|
||||
hsBool IShadeSpan(plMaxNode* node, const hsMatrix44& l2w, const hsMatrix44& w2l, plGeometrySpan& spans);
|
||||
hsBool IShadeGeometrySpans(plMaxNode* node, const hsMatrix44& l2w, const hsMatrix44& w2l, hsTArray<plGeometrySpan *> &spans);
|
||||
|
||||
hsBool IWantsMaps(plMaxNode* node);
|
||||
hsBool IValidateUVWSrc(hsTArray<plGeometrySpan *> &spans) const;
|
||||
|
||||
public:
|
||||
plLightMapGen();
|
||||
virtual ~plLightMapGen();
|
||||
|
||||
#ifdef MF_NEW_RGC
|
||||
void SetRGC(RenderGlobalContext* rgc); // Don't call this ever ever ever
|
||||
#endif // MF_NEW_RGC
|
||||
|
||||
hsBool Open(Interface* ip, TimeValue t, bool forceRegen=true);
|
||||
hsBool InitNode(INode* node, hsBool softShadow=true); // unnecessary when using MakeMaps()
|
||||
hsBool Update(TimeValue t);
|
||||
|
||||
void SetUVWSrc(int i) { fUVWSrc = i; }
|
||||
int GetUVWSrc() const { return fUVWSrc; }
|
||||
|
||||
void SetScale(float f) { fScale = f; }
|
||||
float GetScale() const { return fScale; }
|
||||
|
||||
// Calls to either the global or single must be wrapped in
|
||||
// a call to Open and a call to close. That is, you must first
|
||||
// call Open(), then you can make maps all day, but at the end
|
||||
// of the day, you need to call Close(). Also, if the scene
|
||||
// lighting changes, you need to call Close() and then Open() again.
|
||||
// With the possibility of lights getting deleted from the scene,
|
||||
// you're best off calling Open(), making as many maps as you want
|
||||
// for now, call Close(), and if you decide later you want more,
|
||||
// re-open. There's no protection in here from a user deleting
|
||||
// a light (or any other node) while the shader is Open. For your
|
||||
// own safety and the safety of your fellow passengers, don't
|
||||
// return control to the user until the system is Closed.
|
||||
hsBool MakeMaps(plMaxNode* node, const hsMatrix44& l2w, const hsMatrix44& w2l, hsTArray<plGeometrySpan *>& spans, plErrorMsg *pErrMsg, plConvertSettings *settings);
|
||||
|
||||
Color ShadowPoint(plMaxLightContext& ctx);
|
||||
Color ShadePoint(plMaxLightContext& ctx); // ctx already contains pos & norm
|
||||
Color ShadePoint(plMaxLightContext& ctx, const Point3& p, const Point3& n);
|
||||
Color ShadePoint(plMaxLightContext& ctx, const hsPoint3& p, const hsVector3& n);
|
||||
|
||||
hsBool DeInitNode();
|
||||
hsBool Close();
|
||||
|
||||
static plLightMapGen& Instance();
|
||||
};
|
||||
|
||||
#endif // plLightMapGen_inc
|
140
Sources/Tools/MaxConvert/plMaxLightContext.h
Normal file
140
Sources/Tools/MaxConvert/plMaxLightContext.h
Normal file
@ -0,0 +1,140 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#ifndef plMaxLightContext_inc
|
||||
#define plMaxLightContext_inc
|
||||
|
||||
#include "hsGeometry3.h"
|
||||
|
||||
class plMaxLightContext : public ShadeContext
|
||||
{
|
||||
protected:
|
||||
TimeValue fCurrentTime;
|
||||
|
||||
Box3 fBounds;
|
||||
|
||||
Point3 fPos;
|
||||
Point3 fNorm;
|
||||
Point3 fPertNorm;
|
||||
|
||||
public:
|
||||
plMaxLightContext(const Box3& b, TimeValue t=0)
|
||||
{
|
||||
fBounds = b;
|
||||
fCurrentTime = t;
|
||||
|
||||
doMaps = true;
|
||||
filterMaps = true;
|
||||
backFace = false;
|
||||
xshadeID = 0;
|
||||
mtlNum = 0;
|
||||
}
|
||||
|
||||
void SetPoint(const Point3& p, const Point3& n) { fPos = p; fNorm = fPertNorm = n; } // Must be world space coming in.
|
||||
void SetPoint(const hsPoint3& p, const hsVector3& n) { fPos = Point3(p.fX,p.fY,p.fZ); fNorm = fPertNorm = Point3(n.fX,n.fY,n.fZ); } // Must be world space coming in.
|
||||
|
||||
virtual BOOL InMtlEditor() { return false; } // is this rendering the mtl editor sample sphere?
|
||||
|
||||
virtual LightDesc* Light(int n) { return nil; } // get the nth light.
|
||||
|
||||
virtual TimeValue CurTime() { return fCurrentTime; } // current time value
|
||||
|
||||
virtual int FaceNumber() { return 0; }
|
||||
virtual Point3 Normal() { return fPertNorm; } // interpolated surface normal, in cameara coords: affected by SetNormal()
|
||||
virtual void SetNormal(Point3 p) { fPertNorm = p; } // used for perturbing normal
|
||||
virtual Point3 OrigNormal() { return fNorm; } // original surface normal: not affected by SetNormal();
|
||||
virtual Point3 GNormal() { return fNorm; } // geometric (face) normal
|
||||
|
||||
virtual Point3 V() { return Point3(0.f,1.f,0.f); } // Unit view vector: from camera towards P
|
||||
virtual void SetView(Point3 p) { } // Set the view vector
|
||||
|
||||
virtual Point3 ReflectVector() { return V(); } // reflection vector
|
||||
virtual Point3 RefractVector(float ior) { return V(); } // refraction vector
|
||||
|
||||
virtual Point3 CamPos() { return Point3(0,0,0); } // camera position
|
||||
|
||||
virtual Point3 P() { return fPos; } // point to be shaded;
|
||||
virtual Point3 DP() { return Point3(0,0,0); } // deriv of P, relative to pixel, for AA
|
||||
|
||||
virtual Point3 PObj() { return P(); } // point in obj coords
|
||||
virtual Point3 DPObj() { return DP(); } // deriv of PObj, rel to pixel, for AA
|
||||
virtual Box3 ObjectBox() { return fBounds; } // Object extents box in obj coords
|
||||
virtual Point3 PObjRelBox(); // Point rel to obj box [-1 .. +1 ]
|
||||
virtual Point3 DPObjRelBox() { return Point3(0,0,0); } // deriv of Point rel to obj box [-1 .. +1 ]
|
||||
virtual void ScreenUV(Point2& uv, Point2 &duv) {uv.Set(0,0); duv.Set(0,0); } // screen relative uv (from lower left)
|
||||
virtual IPoint2 ScreenCoord() { return IPoint2(0,0); } // integer screen coordinate (from upper left)
|
||||
|
||||
virtual Point3 UVW(int channel=0) { return Point3(0,0,0); } // return UVW coords for point
|
||||
virtual Point3 DUVW(int channel=0) { return Point3(0,0,0); } // return UVW derivs for point
|
||||
virtual void DPdUVW(Point3 dP[3],int channel=0) { dP[0] = dP[1] = dP[2] = Point3(0,0,0); } // Bump vectors for UVW (camera space)
|
||||
|
||||
virtual void GetBGColor(Color &bgcol, Color& transp, BOOL fogBG=TRUE) { bgcol.Black(); transp.Black(); } // returns Background color, bg transparency
|
||||
|
||||
virtual Point3 PointTo(const Point3& p, RefFrame ito) { return p; }
|
||||
virtual Point3 PointFrom(const Point3& p, RefFrame ifrom) { return p; }
|
||||
virtual Point3 VectorTo(const Point3& p, RefFrame ito) { return p; }
|
||||
virtual Point3 VectorFrom(const Point3& p, RefFrame ifrom) { return p; }
|
||||
};
|
||||
|
||||
inline Point3 plMaxLightContext::PObjRelBox(void)
|
||||
{
|
||||
Point3 q;
|
||||
Point3 p = PObj();
|
||||
Box3 b = ObjectBox();
|
||||
q.x = 2.0f*(p.x-b.pmin.x)/(b.pmax.x-b.pmin.x) - 1.0f;
|
||||
q.y = 2.0f*(p.y-b.pmin.y)/(b.pmax.y-b.pmin.y) - 1.0f;
|
||||
q.z = 2.0f*(p.z-b.pmin.z)/(b.pmax.z-b.pmin.z) - 1.0f;
|
||||
return q;
|
||||
}
|
||||
|
||||
class plMaxRendContext : public RendContext
|
||||
{
|
||||
public:
|
||||
Matrix3 WorldToCam() const { return Matrix3(1); }
|
||||
Color GlobalLightLevel() const { return Color(1.f, 1.f, 1.f); }
|
||||
int Progress(int done, int total) {
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif // plMaxLightContext_inc
|
2559
Sources/Tools/MaxConvert/plMeshConverter.cpp
Normal file
2559
Sources/Tools/MaxConvert/plMeshConverter.cpp
Normal file
File diff suppressed because it is too large
Load Diff
145
Sources/Tools/MaxConvert/plMeshConverter.h
Normal file
145
Sources/Tools/MaxConvert/plMeshConverter.h
Normal file
@ -0,0 +1,145 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// plMeshConverter Class Header //
|
||||
// Static class that converts a Max triMesh object into the geometrySpans //
|
||||
// necessary for a plDrawableIce object. //
|
||||
// //
|
||||
//// Version History /////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Created 4.18.2001 mcn //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _plMeshConverter_h
|
||||
#define _plMeshConverter_h
|
||||
|
||||
#include "Max.h"
|
||||
#include "HeadSpin.h"
|
||||
#include "hsTemplates.h"
|
||||
|
||||
class plMaxNode;
|
||||
class plErrorMsg;
|
||||
class hsConverterUtils;
|
||||
class plMaxNode;
|
||||
class plGeometrySpan;
|
||||
struct hsPoint3;
|
||||
struct hsVector3;
|
||||
struct hsMatrix44;
|
||||
class ISkin;
|
||||
class plConvexVolume;
|
||||
class plMAXVertNormal;
|
||||
class BitmapTex;
|
||||
class hsGMaterial;
|
||||
class plExportMaterialData;
|
||||
|
||||
|
||||
|
||||
//// Class Definition ////////////////////////////////////////////////////////
|
||||
|
||||
class plMeshConverter
|
||||
{
|
||||
private:
|
||||
plMeshConverter();
|
||||
|
||||
static hsBool fWarnBadNormals;
|
||||
static char fWarnBadNormalsMsg[];
|
||||
static hsBool fWarnBadUVs;
|
||||
static char fWarnBadUVsMsg[];
|
||||
static hsBool fWarnSuspiciousUVs;
|
||||
static char fWarnSuspiciousUVsMsg[];
|
||||
static char fTooManyVertsMsg[];
|
||||
static char fTooManyFacesMsg[];
|
||||
|
||||
public:
|
||||
~plMeshConverter();
|
||||
static plMeshConverter& Instance();
|
||||
|
||||
void Init( hsBool save, plErrorMsg *msg );
|
||||
void DeInit( hsBool deInitLongRecur = true );
|
||||
|
||||
void StuffPositionsAndNormals(plMaxNode *node, hsTArray<hsPoint3> *pos, hsTArray<hsVector3> *normals);
|
||||
plConvexVolume *CreateConvexVolume( plMaxNode *node );
|
||||
// doPreshading - If true, do crappy flat shading now (since we won't do any shading later)
|
||||
hsBool CreateSpans( plMaxNode *node, hsTArray<plGeometrySpan *> &spanArray, bool doPreshading );
|
||||
|
||||
private:
|
||||
bool IValidateUVs(plMaxNode* node);
|
||||
|
||||
void ISetBumpUvs(Int16 uvChan, hsTArray<plMAXVertNormal>& vertDPosDuvCache, TVFace* tvFace, UInt32 smGroup,
|
||||
hsPoint3* uvs1, hsPoint3* uvs2, hsPoint3* uvs3);
|
||||
void ISetBumpUvSrcs(hsTArray<hsTArray<plExportMaterialData> *>& ourMaterials,
|
||||
hsTArray<Int16>& bumpLayIdx, hsTArray<Int16>& bumpLayChan, hsTArray<Int16>& bumpDuChan, hsTArray<Int16>& bumpDvChan);
|
||||
void ISetWaterDecEnvUvSrcs(hsTArray<hsTArray<plExportMaterialData> *>& ourMaterials,
|
||||
hsTArray<Int16>& bumpLayIdx, hsTArray<Int16>& bumpLayChan, hsTArray<Int16>& bumpDuChan, hsTArray<Int16>& bumpDvChan);
|
||||
void ISmoothUVGradients(plMaxNode* node, Mesh* mesh,
|
||||
hsTArray<hsTArray<plExportMaterialData> *>& ourMaterials,
|
||||
hsTArray<Int16>& bumpLayIdx, hsTArray<Int16>& bumpLayChan,
|
||||
hsTArray<plMAXVertNormal>* vertDPosDuCache, hsTArray<plMAXVertNormal>* vertDPosDvCache);
|
||||
Point3 IGetUvGradient(plMaxNode* node, const hsMatrix44& uvXform44, Int16 bmpUvwSrc,
|
||||
Mesh *mesh, int faceIdx,
|
||||
int iUV);
|
||||
|
||||
int IGenerateUVs( plMaxNode *node, Mtl *maxMtl, Mesh *mesh, int faceIdx, int numChan, int numBlend,
|
||||
hsPoint3 *uvs1, hsPoint3 *uvs2, hsPoint3 *uvs3 );
|
||||
void IGetUVTransform( plMaxNode *node, Mtl *mtl, Matrix3 *uvTransform, int which );
|
||||
|
||||
UInt32 ICreateHexColor( float r, float g, float b );
|
||||
UInt32 ISetHexAlpha( UInt32 color, float alpha );
|
||||
|
||||
Mesh* IGetNodeMesh(plMaxNode *node);
|
||||
void IDeleteTempGeometry();
|
||||
Mesh* IDuplicate2Sided(plMaxNode *node, Mesh* mesh);
|
||||
|
||||
Interface *fInterface;
|
||||
hsConverterUtils& fConverterUtils;
|
||||
plErrorMsg *fErrorMsg;
|
||||
hsBool fIsInitialized;
|
||||
|
||||
// Non-nil if we converted the MAX object and have to delete it when we're done
|
||||
TriObject *fTriObjToDelete;
|
||||
// Non-nil if we made a copy to mess with that we need to delete when we're done
|
||||
Mesh *fMeshToDelete;
|
||||
};
|
||||
|
||||
#endif // _plMeshConverter_h
|
221
Sources/Tools/MaxConvert/plRenderGlobalContext.cpp
Normal file
221
Sources/Tools/MaxConvert/plRenderGlobalContext.cpp
Normal file
@ -0,0 +1,221 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#include "HeadSpin.h"
|
||||
#include "Max.h"
|
||||
|
||||
#include "../MaxMain/plMaxNode.h"
|
||||
#include "plRenderGlobalContext.h"
|
||||
|
||||
plRenderGlobalContext::plRenderGlobalContext(Interface* ip, TimeValue t)
|
||||
{
|
||||
fInterface = ip;
|
||||
|
||||
renderer = ip->GetProductionRenderer();
|
||||
projType = PROJ_PERSPECTIVE;
|
||||
devWidth = 640;
|
||||
devHeight = 480;
|
||||
xscale = 1.6f;
|
||||
yscale = -1.6f;
|
||||
xc = 320.f;
|
||||
yc = 240.f;
|
||||
antialias = 1;
|
||||
camToWorld.IdentityMatrix();
|
||||
worldToCam.IdentityMatrix();
|
||||
nearRange = 0;
|
||||
farRange = 10000.f;
|
||||
devAspect = 1.f; // PIXEL aspect ratio of device pixel H/W
|
||||
frameDur = 1.f;
|
||||
envMap = nil;
|
||||
globalLightLevel.White();
|
||||
atmos = nil;
|
||||
pToneOp = nil; // The tone operator, may be NULL
|
||||
time = t;
|
||||
wireMode = false; // wire frame render mode?
|
||||
wire_thick = 1.f; // global wire thickness
|
||||
force2Side = false; // is force two-sided rendering enabled
|
||||
inMtlEdit = false; // rendering in mtl editor?
|
||||
fieldRender = false; // are we rendering fields
|
||||
first_field = 1; // is this the first field or the second?
|
||||
field_order = 1; // which field is first: 0->even first, 1->odd first
|
||||
|
||||
objMotBlur = true; // is object motion blur enabled
|
||||
nBlurFrames = 10; // number of object motion blur time slices
|
||||
|
||||
SetRenderElementMgr(ip->GetRenderElementMgr(RS_Production));
|
||||
|
||||
}
|
||||
|
||||
plRenderGlobalContext::~plRenderGlobalContext()
|
||||
{
|
||||
int i;
|
||||
for( i = 0; i < fInstList.GetCount(); i++ )
|
||||
{
|
||||
fInstList[i].Cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
void plRenderGlobalContext::Update(TimeValue t)
|
||||
{
|
||||
time = t;
|
||||
|
||||
int i;
|
||||
for( i = 0; i < fInstList.GetCount(); i++ )
|
||||
fInstList[i].Update(time);
|
||||
}
|
||||
|
||||
void plRenderGlobalContext::MakeRenderInstances(plMaxNode* root, TimeValue t)
|
||||
{
|
||||
time = t;
|
||||
int i;
|
||||
for( i = 0; i < root->NumberOfChildren(); i++ )
|
||||
IMakeRenderInstances((plMaxNode*)root->GetChildNode(i), t, false);
|
||||
|
||||
for( i = 0; i < fInstList.GetCount() - 1; i++ )
|
||||
fInstList[i].SetNext(&fInstList[i+1]);
|
||||
}
|
||||
|
||||
void plRenderGlobalContext::IMakeRenderInstances(plMaxNode* node, TimeValue t, hsBool isBarney)
|
||||
{
|
||||
const char* dbgNodeName = node->GetName();
|
||||
if( !isBarney )
|
||||
isBarney = node->GetIsBarney();
|
||||
|
||||
hsBool doMe = isBarney || (node->CanConvert() && node->GetDrawable());
|
||||
|
||||
if( !doMe )
|
||||
return;
|
||||
|
||||
int idx = fInstList.GetCount();
|
||||
|
||||
plRenderInstance* inst = fInstList.Push();
|
||||
|
||||
if( !inst->GetFromNode(node, t, idx) )
|
||||
fInstList.Pop();
|
||||
|
||||
int i;
|
||||
for( i = 0; i < node->NumberOfChildren(); i++ )
|
||||
IMakeRenderInstances((plMaxNode *)node->GetChildNode(i), t, isBarney);
|
||||
}
|
||||
|
||||
void plRenderGlobalContext::IntersectRay(RenderInstance *inst, Ray& origRay, ISect &isct, ISectList &xplist, BOOL findExit)
|
||||
{
|
||||
const float kFarAway = 1.e5f;
|
||||
Ray ray;
|
||||
if( findExit )
|
||||
{
|
||||
ray.p = origRay.p + origRay.dir * kFarAway;
|
||||
ray.dir = -ray.dir;
|
||||
}
|
||||
else
|
||||
{
|
||||
ray = origRay;
|
||||
}
|
||||
float at;
|
||||
Point3 norm;
|
||||
DWORD faceIdx;
|
||||
Point3 bary;
|
||||
int hit = inst->mesh->IntersectRay(ray, at, norm, faceIdx, bary);
|
||||
if( hit )
|
||||
{
|
||||
ISect thisHit;
|
||||
thisHit.t = findExit ? kFarAway - at : at;
|
||||
thisHit.exit = findExit;
|
||||
thisHit.backFace = findExit;
|
||||
thisHit.inst = inst;
|
||||
thisHit.fnum = faceIdx;
|
||||
thisHit.bc = bary;
|
||||
Point3 worldP = (ray.p + at * ray.dir);
|
||||
thisHit.p = inst->GetINode()->GetObjectTM(time) * worldP;
|
||||
thisHit.pc = worldToCam * thisHit.p;
|
||||
|
||||
thisHit.mtlNum = inst->mesh->faces[faceIdx].getMatID();
|
||||
Mtl* mtl = inst->GetINode()->GetMtl();
|
||||
thisHit.matreq = mtl ? mtl->Requirements(thisHit.mtlNum) : 0;
|
||||
|
||||
thisHit.next = nil;
|
||||
|
||||
if( thisHit.matreq & (MTLREQ_TRANSP | MTLREQ_ADDITIVE_TRANSP) )
|
||||
{
|
||||
// advance the ray and try again. This one goes in the xplist.
|
||||
ISect* xHit = GetNewISect();
|
||||
*xHit = thisHit;
|
||||
xplist.Add(xHit);
|
||||
|
||||
const float kAdvanceHack = 0.5f;
|
||||
Ray newRay;
|
||||
newRay.p = origRay.p + origRay.dir * (thisHit.t + kAdvanceHack);
|
||||
newRay.dir = origRay.dir;
|
||||
IntersectRay(inst, newRay, isct, xplist, findExit);
|
||||
}
|
||||
else
|
||||
{
|
||||
xplist.Prune(thisHit.t);
|
||||
isct = thisHit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOL plRenderGlobalContext::IntersectWorld(Ray &ray, int skipID, ISect &hit, ISectList &xplist, int blurFrame)
|
||||
{
|
||||
hit.t = -1.f;
|
||||
xplist.Init();
|
||||
int i;
|
||||
for( i = 0; i < fInstList.GetCount(); i++ )
|
||||
{
|
||||
if( skipID != i )
|
||||
{
|
||||
ISect thisHit;
|
||||
hit.t = -1.f;
|
||||
IntersectRay(&fInstList[i], ray, thisHit, xplist, false);
|
||||
if( thisHit.t >= 0 )
|
||||
{
|
||||
if( (hit.t < 0) || (thisHit.t < hit.t) )
|
||||
{
|
||||
// grab our new winner.
|
||||
hit = thisHit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (hit.t >= 0) || !xplist.IsEmpty();
|
||||
}
|
73
Sources/Tools/MaxConvert/plRenderGlobalContext.h
Normal file
73
Sources/Tools/MaxConvert/plRenderGlobalContext.h
Normal file
@ -0,0 +1,73 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#ifndef plRenderGlobalContext_inc
|
||||
#define plRenderGlobalContext_inc
|
||||
|
||||
#include "hsTemplates.h"
|
||||
#include "plRenderInstance.h"
|
||||
|
||||
class plRenderGlobalContext : public RenderGlobalContext
|
||||
{
|
||||
protected:
|
||||
Interface* fInterface;
|
||||
|
||||
hsTArray<plRenderInstance> fInstList;
|
||||
|
||||
void IMakeRenderInstances(plMaxNode* node, TimeValue t, hsBool isBarney);
|
||||
|
||||
public:
|
||||
plRenderGlobalContext(Interface* ip, TimeValue t);
|
||||
~plRenderGlobalContext();
|
||||
|
||||
void Update(TimeValue t);
|
||||
|
||||
void MakeRenderInstances(plMaxNode* root, TimeValue t);
|
||||
|
||||
virtual int NumRenderInstances() { return fInstList.GetCount(); }
|
||||
virtual RenderInstance* GetRenderInstance( int i ) { return i < fInstList.GetCount() ? &fInstList[i] : nil; }
|
||||
|
||||
virtual void IntersectRay(RenderInstance *inst, Ray& ray, ISect &isct, ISectList &xpList, BOOL findExit);
|
||||
virtual BOOL IntersectWorld(Ray &ray, int skipID, ISect &hit, ISectList &xplist, int blurFrame = NO_MOTBLUR);
|
||||
};
|
||||
|
||||
#endif // plRenderGlobalContext_inc
|
316
Sources/Tools/MaxConvert/plRenderInstance.cpp
Normal file
316
Sources/Tools/MaxConvert/plRenderInstance.cpp
Normal file
@ -0,0 +1,316 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#include "hsTypes.h"
|
||||
#include "Max.h"
|
||||
|
||||
#include "plRenderInstance.h"
|
||||
|
||||
class plNilView : public View
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
Point2 ViewToScreen(Point3 p) { return Point2(p.x,p.y); }
|
||||
|
||||
plNilView()
|
||||
{
|
||||
projType = 1;
|
||||
fov = hsScalarPI * 0.25f;
|
||||
pixelSize = 1.f;
|
||||
affineTM.IdentityMatrix();
|
||||
worldToView.IdentityMatrix();
|
||||
screenW=640.0f; screenH = 480.0f;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
static plNilView nilView;
|
||||
|
||||
plRenderInstance::plRenderInstance()
|
||||
: fNext(nil),
|
||||
fNode(nil),
|
||||
fObject(nil),
|
||||
fDeleteMesh(false)
|
||||
{
|
||||
mtl = nil;
|
||||
mesh = nil;
|
||||
flags = 0;
|
||||
wireSize = 1.f;
|
||||
vis = 1.f;
|
||||
nodeID = 0;
|
||||
objMotBlurFrame = 0;
|
||||
objBlurID = 0;
|
||||
objToWorld.IdentityMatrix();
|
||||
objToCam.IdentityMatrix();
|
||||
normalObjToCam.IdentityMatrix();
|
||||
camToObj.IdentityMatrix();
|
||||
obBox.Init();
|
||||
center = Point3(0,0,0);
|
||||
radsq = 0;
|
||||
}
|
||||
|
||||
plRenderInstance::~plRenderInstance()
|
||||
{
|
||||
}
|
||||
|
||||
void plRenderInstance::Cleanup()
|
||||
{
|
||||
if( mesh && fDeleteMesh )
|
||||
{
|
||||
mesh->DeleteThis();
|
||||
mesh = nil;
|
||||
fDeleteMesh = false;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL plRenderInstance::Update(TimeValue& t)
|
||||
{
|
||||
fObject = fNode->EvalWorldState(t).obj;
|
||||
if( !fObject )
|
||||
return false;
|
||||
|
||||
// this shouldn't happen, we shouldn't be trying to make
|
||||
// renderinstances from non GEOMOBJECT's
|
||||
if( fObject->SuperClassID() != GEOMOBJECT_CLASS_ID )
|
||||
return false;
|
||||
|
||||
if( mesh && fDeleteMesh )
|
||||
{
|
||||
mesh->DeleteThis();
|
||||
mesh = nil;
|
||||
}
|
||||
fDeleteMesh = false;
|
||||
mesh = ((GeomObject*)fObject)->GetRenderMesh(t, fNode, nilView, fDeleteMesh);
|
||||
if( !mesh )
|
||||
return false;
|
||||
|
||||
vis = fNode->GetVisibility(t);
|
||||
if( vis < 0.0f )
|
||||
{
|
||||
vis = 0.0f;
|
||||
SetFlag(INST_HIDE, 1);
|
||||
return false;
|
||||
}
|
||||
if (vis > 1.0f) vis = 1.0f;
|
||||
SetFlag(INST_HIDE, 0);
|
||||
|
||||
objMotBlurFrame = NO_MOTBLUR;
|
||||
objBlurID = 0;
|
||||
|
||||
objToWorld = fNode->GetObjectTM(t);
|
||||
objToCam = objToWorld;
|
||||
camToObj = Inverse(objToCam);
|
||||
|
||||
normalObjToCam.IdentityMatrix();
|
||||
Matrix3 inv = camToObj;
|
||||
int i;
|
||||
for( i = 0; i < 3; i++ )
|
||||
normalObjToCam.SetRow(i, inv.GetColumn3(i));
|
||||
|
||||
obBox = mesh->getBoundingBox(nil);
|
||||
center = obBox.Center();
|
||||
radsq = LengthSquared(obBox.Width());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOL plRenderInstance::GetFromNode(INode* node, TimeValue& t, int idx)
|
||||
{
|
||||
fNext = nil;
|
||||
|
||||
fValid = Interval(t, t);
|
||||
|
||||
fNode = node;
|
||||
mtl = node->GetMtl();
|
||||
if( mtl )
|
||||
{
|
||||
wireSize = mtl->WireSize();
|
||||
}
|
||||
|
||||
nodeID = idx;
|
||||
|
||||
ClearLights();
|
||||
|
||||
return Update(t);
|
||||
}
|
||||
|
||||
BOOL plRenderInstance::CastsShadowsFrom(const ObjLightDesc& constLt)
|
||||
{
|
||||
ObjLightDesc& lt = const_cast<ObjLightDesc&>(constLt);
|
||||
if( !fNode->CastShadows() )
|
||||
return false;
|
||||
|
||||
if( !lt.ls.shadow )
|
||||
return false;
|
||||
|
||||
if( lt.GetExclList() && lt.GetExclList()->TestFlag(NT_AFFECT_SHADOWCAST) )
|
||||
{
|
||||
int idx = lt.GetExclList()->FindNode(fNode);
|
||||
BOOL isInc = lt.GetExclList()->TestFlag(NT_INCLUDE);
|
||||
|
||||
if( idx >= 0 )
|
||||
{
|
||||
return isInc;
|
||||
}
|
||||
else
|
||||
{
|
||||
return !isInc;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Point3 plRenderInstance::GetFaceNormal(int fnum)
|
||||
{
|
||||
Face* f = &mesh->faces[fnum];
|
||||
Point3 a = GetCamVert(f->v[1]) - GetCamVert(f->v[0]);
|
||||
Point3 b = GetCamVert(f->v[2]) - GetCamVert(f->v[0]);
|
||||
|
||||
Point3 n = CrossProd(a, b).Normalize();
|
||||
return n;
|
||||
}
|
||||
|
||||
Point3 plRenderInstance::GetFaceVertNormal(int fnum, int vertNum)
|
||||
{
|
||||
Point3 retNorm;
|
||||
|
||||
int smGroup=0;
|
||||
|
||||
Face* f = &mesh->faces[fnum];
|
||||
|
||||
// Get the rendered vertex. Don't use the device position, fPos.
|
||||
RVertex &rv = mesh->getRVert(f->v[vertNum]);
|
||||
|
||||
// Number of normals at the vertex
|
||||
int numNormalsAtVert = (rv.rFlags & NORCT_MASK);
|
||||
|
||||
// Specified normal ?
|
||||
int specNrml = (rv.rFlags & SPECIFIED_NORMAL);
|
||||
|
||||
if (specNrml || (numNormalsAtVert == 1))
|
||||
{
|
||||
// The normal case is one normal per vertex (a vertex not beng shared by more than one smoothing group)
|
||||
// We'll assign vertex normals here.
|
||||
// If the object is faceted, this will be the same as the face normal.
|
||||
retNorm = rv.rn.getNormal();
|
||||
}
|
||||
else
|
||||
{
|
||||
int found = 0;
|
||||
for(int j=0;j<numNormalsAtVert; j++)
|
||||
{
|
||||
smGroup = rv.ern[j].getSmGroup();
|
||||
// Since this vertex is shared by more than one smoothing group, it has multiple normals.
|
||||
// This is fairly rare and doesn't occur in faceted objects.
|
||||
// Just pick the first normal and use that as the vertex normal.
|
||||
int faceSmGroup = f->getSmGroup();
|
||||
if ((smGroup & faceSmGroup) == faceSmGroup)
|
||||
{
|
||||
retNorm = rv.ern[j].getNormal();
|
||||
found++;
|
||||
|
||||
// NOTE: Remove this to really check smoothing groups
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
retNorm = retNorm * normalObjToCam;
|
||||
retNorm.Normalize();
|
||||
return retNorm;
|
||||
}
|
||||
|
||||
Point3 plRenderInstance::GetCamVert(int vertnum)
|
||||
{
|
||||
return objToCam*mesh->verts[vertnum];
|
||||
}
|
||||
|
||||
void plRenderInstance::GetObjVerts(int fnum, Point3 obp[3])
|
||||
{
|
||||
Face* f = &mesh->faces[fnum];
|
||||
obp[0] = mesh->verts[f->v[0]];
|
||||
obp[1] = mesh->verts[f->v[1]];
|
||||
obp[2] = mesh->verts[f->v[2]];
|
||||
}
|
||||
|
||||
void plRenderInstance::GetCamVerts(int fnum, Point3 cp[3])
|
||||
{
|
||||
Face* f = &mesh->faces[fnum];
|
||||
cp[0] = objToCam*mesh->verts[f->v[0]];
|
||||
cp[1] = objToCam*mesh->verts[f->v[1]];
|
||||
cp[2] = objToCam*mesh->verts[f->v[2]];
|
||||
}
|
||||
|
||||
Mtl* plRenderInstance::GetMtl(int fnum)
|
||||
{
|
||||
if( !mtl )
|
||||
return nil;
|
||||
|
||||
if( TestFlag(INST_MTL_BYFACE) )
|
||||
{
|
||||
if( mtl->ClassID() != Class_ID(MULTI_CLASS_ID,0) )
|
||||
return mtl;
|
||||
|
||||
Face* f = &mesh->faces[fnum];
|
||||
int matIndex = f->getMatID();
|
||||
return mtl->GetSubMtl(matIndex);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return mtl;
|
||||
}
|
||||
}
|
||||
|
||||
ULONG plRenderInstance::MtlRequirements(int mtlNum, int faceNum)
|
||||
{
|
||||
if( !mtl )
|
||||
return 0;
|
||||
|
||||
if( TestFlag(INST_MTL_BYFACE) )
|
||||
{
|
||||
Mtl* faceMtl = GetMtl(faceNum);
|
||||
return faceMtl ? faceMtl->Requirements(mtlNum) : 0;
|
||||
}
|
||||
return mtl->Requirements(mtlNum);
|
||||
}
|
103
Sources/Tools/MaxConvert/plRenderInstance.h
Normal file
103
Sources/Tools/MaxConvert/plRenderInstance.h
Normal file
@ -0,0 +1,103 @@
|
||||
/*==LICENSE==*
|
||||
|
||||
CyanWorlds.com Engine - MMOG client, server and tools
|
||||
Copyright (C) 2011 Cyan Worlds, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
||||
or by snail mail at:
|
||||
Cyan Worlds, Inc.
|
||||
14617 N Newport Hwy
|
||||
Mead, WA 99021
|
||||
|
||||
*==LICENSE==*/
|
||||
|
||||
#ifndef plRenderInstance_inc
|
||||
#define plRenderInstance_inc
|
||||
|
||||
#include "hsTemplates.h"
|
||||
|
||||
class plRenderInstance : public RenderInstance
|
||||
{
|
||||
protected:
|
||||
plRenderInstance* fNext;
|
||||
Interval fValid;
|
||||
|
||||
INode* fNode;
|
||||
Object* fObject;
|
||||
|
||||
BOOL fDeleteMesh;
|
||||
|
||||
hsTArray<LightDesc*> fLights;
|
||||
public:
|
||||
plRenderInstance();
|
||||
virtual ~plRenderInstance();
|
||||
|
||||
BOOL GetFromNode(INode* node, TimeValue& t, int idx);
|
||||
BOOL Update(TimeValue& t);
|
||||
void SetNext(plRenderInstance* n) { fNext = n; }
|
||||
void Cleanup();
|
||||
|
||||
virtual RenderInstance *Next() { return fNext; } // next in list
|
||||
|
||||
virtual Interval MeshValidity() { return fValid; }
|
||||
|
||||
virtual int NumLights() { return fLights.GetCount(); }
|
||||
virtual LightDesc *Light(int n) { return fLights[n]; }
|
||||
virtual void AddLight(LightDesc* l) { fLights.Append(l); }
|
||||
virtual void ClearLights() { fLights.SetCount(0); }
|
||||
|
||||
virtual BOOL CastsShadowsFrom(const ObjLightDesc& lt); // is lt shadowed by this instance?
|
||||
|
||||
virtual INode *GetINode() { return fNode; } // get INode for instance
|
||||
virtual Object *GetEvalObject() { return fObject; } // evaluated object for instance
|
||||
|
||||
virtual Point3 GetFaceNormal(int faceNum); // geometric normal in camera coords
|
||||
virtual Point3 GetFaceVertNormal(int faceNum, int vertNum); // camera coords
|
||||
virtual void GetFaceVertNormals(int faceNum, Point3 n[3]) // camera coords
|
||||
{
|
||||
n[0] = GetFaceVertNormal(faceNum, 0);
|
||||
n[1] = GetFaceVertNormal(faceNum, 1);
|
||||
n[2] = GetFaceVertNormal(faceNum, 2);
|
||||
}
|
||||
virtual Point3 GetCamVert(int vertnum); // coord for vertex in camera coords
|
||||
virtual void GetObjVerts(int fnum, Point3 obp[3]); // vertices of face in object coords
|
||||
virtual void GetCamVerts(int fnum, Point3 cp[3]); // vertices of face in camera(view) coords
|
||||
|
||||
// Material-by-face access
|
||||
// Objects can provide a material as a function of face number via the IChkMtlAPI interface (chkmtlapi.h).
|
||||
// This method will return RenderInstance::mtl if flag INST_MTL_BYFACE is not set. If INST_MTL_BYFACE is
|
||||
// set it will return the proper by-face mtl. // DS 4/3/00
|
||||
virtual Mtl *GetMtl(int faceNum);
|
||||
virtual ULONG MtlRequirements(int mtlNum, int faceNum); // node's mtl requirements. DS 3/31/00: added faceNum to support mtl-per-face objects
|
||||
};
|
||||
|
||||
#endif // plRenderInstance_inc
|
Reference in New Issue
Block a user