2
3
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:
rarified
2021-05-15 12:49:46 -06:00
parent c3f4a640a3
commit 96903e8dca
4002 changed files with 159 additions and 644 deletions

View 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;
}

View 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

View 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);
}

View 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

File diff suppressed because it is too large Load Diff

View 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> &times );
hsBool IGetGeomKeyTimes( plMaxNode *node, Tab<TimeValue> &times );
void IGetGeomKeyTimesRecur( Animatable *anim, Tab<TimeValue> &times );
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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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;
}

View 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

View 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;
}

View 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 );
};

View 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();
}
}
}

View 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

View 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;
}

View 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

View 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);
}
}

View 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

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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();
}

View 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

View 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);
}

View 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