git.diff (133,696 bytes)
2011-04-01 02:20
diff --git a/rts/Game/Camera.cpp b/rts/Game/Camera.cpp
index 3a13aae..aec1220 100644
--- a/rts/Game/Camera.cpp
+++ b/rts/Game/Camera.cpp
@@ -132,9 +132,8 @@ void CCamera::Update(bool freeze, bool resetUp)
const float gndHeight = ground->GetHeightAboveWater(pos.x, pos.z);
const float rangemod = 1.0f + std::max(0.0f, pos.y - gndHeight - 500.0f) * 0.0003f;
- const float zNear = (CGlobalRendering::NEAR_PLANE * rangemod);
-
- globalRendering->viewRange = CGlobalRendering::MAX_VIEW_RANGE * rangemod;
+ const float zNear = (NEAR_PLANE * rangemod);
+ globalRendering->viewRange = MAX_VIEW_RANGE * rangemod;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
diff --git a/rts/Game/Game.cpp b/rts/Game/Game.cpp
index 4e046dc..85ea86f 100644
--- a/rts/Game/Game.cpp
+++ b/rts/Game/Game.cpp
@@ -217,6 +217,7 @@ CR_REG_METADATA(CGame,(
CGame::CGame(const std::string& mapname, const std::string& modName, ILoadSaveHandler* saveFile) :
+ finishedLoading(false),
gameDrawMode(gameNotDrawing),
defsParser(NULL),
fps(0),
@@ -230,7 +231,6 @@ CGame::CGame(const std::string& mapname, const std::string& modName, ILoadSaveHa
gameOver(false),
noSpectatorChat(false),
- finishedLoading(false),
infoConsole(NULL),
consoleHistory(NULL),
@@ -708,23 +708,20 @@ void CGame::ResizeEvent()
}
-int CGame::KeyPressed(unsigned short key, bool isRepeat)
+int CGame::KeyPressed(unsigned short k, bool isRepeat)
{
if (!gameOver && !isRepeat) {
playerHandler->Player(gu->myPlayerNum)->currentStats.keyPresses++;
}
- // Get the list of possible key actions
- const CKeySet ks(key, false);
- const CKeyBindings::ActionList& actionList = keyBindings->GetActionList(ks);
-
if (!hotBinding.empty()) {
- if (key == SDLK_ESCAPE) {
+ if (k == SDLK_ESCAPE) {
hotBinding.clear();
}
- else if (!keyCodes->IsModifier(key) && (key != keyBindings->GetFakeMetaKey())) {
+ else if (!keyCodes->IsModifier(k) && (k != keyBindings->GetFakeMetaKey())) {
+ CKeySet ks(k, false);
string cmd = "bind";
- cmd += " " + ks.GetString(false);
+ cmd += " " + ks.GetString(false) ;
cmd += " " + hotBinding;
keyBindings->Command(cmd);
hotBinding.clear();
@@ -733,15 +730,173 @@ int CGame::KeyPressed(unsigned short key, bool isRepeat)
return 0;
}
+ // Get the list of possible key actions
+ CKeySet ks(k, false);
+ const CKeyBindings::ActionList& actionList = keyBindings->GetActionList(ks);
+
if (userWriting) {
- for (unsigned int actionIndex = 0; actionIndex < actionList.size(); actionIndex++) {
- if (ProcessKeyPressAction(key, actionList[actionIndex])) {
- // the key was used, ignore it (ex: alt+a)
- ignoreNextChar = (actionIndex < (actionList.size() - 1));
+ unsigned int actionIndex;
+ for (actionIndex = 0; actionIndex < actionList.size(); actionIndex++) {
+ const Action& action = actionList[actionIndex];
+
+ if (action.command == "edit_return") {
+ userWriting=false;
+ writingPos = 0;
+
+ if (k == SDLK_RETURN) {
+ keyInput->SetKeyState(k, 0); //prevent game start when server chats
+ }
+ if (chatting) {
+ string command;
+ if ((userInput.find_first_of("aAsS") == 0) && (userInput[1] == ':')) {
+ command = userInput.substr(2);
+ } else {
+ command = userInput;
+ }
+ if ((command[0] == '/') && (command[1] != '/')) {
+ // execute an action
+ consoleHistory->AddLine(command);
+ const string actionLine = command.substr(1); // strip the '/'
+ chatting = false;
+ userInput = "";
+ writingPos = 0;
+ logOutput.Print(command);
+ CKeySet ks(k, false);
+ Action fakeAction(actionLine);
+ ActionPressed(fakeAction, ks, isRepeat);
+ }
+ }
+ break;
+ }
+ else if ((action.command == "edit_escape") &&
+ (chatting || inMapDrawer->wantLabel)) {
+ if (chatting) {
+ consoleHistory->AddLine(userInput);
+ }
+ userWriting=false;
+ chatting=false;
+ inMapDrawer->wantLabel=false;
+ userInput="";
+ writingPos = 0;
+ break;
+ }
+ else if (action.command == "edit_complete") {
+ string head = userInput.substr(0, writingPos);
+ string tail = userInput.substr(writingPos);
+ const vector<string> &partials = wordCompletion->Complete(head);
+ userInput = head + tail;
+ writingPos = (int)head.length();
+ if (!partials.empty()) {
+ string msg;
+ for (unsigned int i = 0; i < partials.size(); i++) {
+ msg += " ";
+ msg += partials[i];
+ }
+ logOutput.Print(msg);
+ }
+ break;
+ }
+ else if (action.command == "chatswitchall") {
+ if ((userInput.find_first_of("aAsS") == 0) && (userInput[1] == ':')) {
+ userInput = userInput.substr(2);
+ writingPos = std::max(0, writingPos - 2);
+ }
+ userInputPrefix = "";
+ break;
+ }
+ else if (action.command == "chatswitchally") {
+ if ((userInput.find_first_of("aAsS") == 0) && (userInput[1] == ':')) {
+ userInput[0] = 'a';
+ } else {
+ userInput = "a:" + userInput;
+ writingPos += 2;
+ }
+ userInputPrefix = "a:";
+ break;
+ }
+ else if (action.command == "chatswitchspec") {
+ if ((userInput.find_first_of("aAsS") == 0) && (userInput[1] == ':')) {
+ userInput[0] = 's';
+ } else {
+ userInput = "s:" + userInput;
+ writingPos += 2;
+ }
+ userInputPrefix = "s:";
+ break;
+ }
+ else if (action.command == "pastetext") {
+ if (!action.extra.empty()) {
+ userInput.insert(writingPos, action.extra);
+ writingPos += action.extra.length();
+ } else {
+ PasteClipboard();
+ }
+ break;
+ }
+
+ else if (action.command == "edit_backspace") {
+ if (!userInput.empty() && (writingPos > 0)) {
+ userInput.erase(writingPos - 1, 1);
+ writingPos--;
+ }
+ break;
+ }
+ else if (action.command == "edit_delete") {
+ if (!userInput.empty() && (writingPos < (int)userInput.size())) {
+ userInput.erase(writingPos, 1);
+ }
+ break;
+ }
+ else if (action.command == "edit_home") {
+ writingPos = 0;
+ break;
+ }
+ else if (action.command == "edit_end") {
+ writingPos = (int)userInput.length();
+ break;
+ }
+ else if (action.command == "edit_prev_char") {
+ writingPos = std::max(0, std::min((int)userInput.length(), writingPos - 1));
+ break;
+ }
+ else if (action.command == "edit_next_char") {
+ writingPos = std::max(0, std::min((int)userInput.length(), writingPos + 1));
+ break;
+ }
+ else if (action.command == "edit_prev_word") {
+ // prev word
+ const char* s = userInput.c_str();
+ int p = writingPos;
+ while ((p > 0) && !isalnum(s[p - 1])) { p--; }
+ while ((p > 0) && isalnum(s[p - 1])) { p--; }
+ writingPos = p;
+ break;
+ }
+ else if (action.command == "edit_next_word") {
+ const int len = (int)userInput.length();
+ const char* s = userInput.c_str();
+ int p = writingPos;
+ while ((p < len) && !isalnum(s[p])) { p++; }
+ while ((p < len) && isalnum(s[p])) { p++; }
+ writingPos = p;
+ break;
+ }
+ else if ((action.command == "edit_prev_line") && chatting) {
+ userInput = consoleHistory->PrevLine(userInput);
+ writingPos = (int)userInput.length();
+ break;
+ }
+ else if ((action.command == "edit_next_line") && chatting) {
+ userInput = consoleHistory->NextLine(userInput);
+ writingPos = (int)userInput.length();
break;
}
}
+ if (actionIndex != actionList.size()) {
+ ignoreNextChar = true; // the key was used, ignore it (ex: alt+a)
+ }
+
return 0;
}
@@ -749,15 +904,15 @@ int CGame::KeyPressed(unsigned short key, bool isRepeat)
std::deque<CInputReceiver*>& inputReceivers = GetInputReceivers();
std::deque<CInputReceiver*>::iterator ri;
for (ri = inputReceivers.begin(); ri != inputReceivers.end(); ++ri) {
- CInputReceiver* recv = *ri;
- if (recv && recv->KeyPressed(key, isRepeat)) {
+ CInputReceiver* recv=*ri;
+ if (recv && recv->KeyPressed(k, isRepeat)) {
return 0;
}
}
// try our list of actions
- for (unsigned int i = 0; i < actionList.size(); ++i) {
- if (ActionPressed(key, actionList[i], isRepeat)) {
+ for (int i = 0; i < (int)actionList.size(); ++i) {
+ if (ActionPressed(actionList[i], ks, isRepeat)) {
return 0;
}
}
@@ -1609,12 +1764,9 @@ void CGame::SimFrame() {
m_validateAllAllocUnits();
#endif
- // Important: gs->frameNum must be updated *before* GameFrame is called,
- // or any call-outs called by Lua will see a stale gs->frameNum.
- // (e.g. effective TTL of CEGs emitted in GameFrame will be reduced...)
- // It must still be passed the old frameNum because Lua may depend on it.
- // (e.g. initialization in frame 0...)
- eventHandler.GameFrame(gs->frameNum++);
+ eventHandler.GameFrame(gs->frameNum);
+
+ gs->frameNum++;
if (!skipping) {
infoConsole->Update();
diff --git a/rts/Game/Game.h b/rts/Game/Game.h
index bfcb914..5837b90 100644
--- a/rts/Game/Game.h
+++ b/rts/Game/Game.h
@@ -47,7 +47,6 @@ private:
public:
CGame(const std::string& mapname, const std::string& modName, ILoadSaveHandler* saveFile);
- virtual ~CGame();
bool Draw();
bool DrawMT();
@@ -57,22 +56,20 @@ public:
/// Called when a key is released by the user
int KeyReleased(unsigned short k);
/// Called when the key is pressed by the user (can be called several times due to key repeat)
- int KeyPressed(unsigned short k, bool isRepeat);
+ int KeyPressed(unsigned short k,bool isRepeat);
void ResizeEvent();
+ virtual ~CGame();
-
- bool ProcessCommandText(unsigned int key, const std::string& command);
- bool ProcessKeyPressAction(unsigned int key, const Action& action);
-
- bool ActionPressed(unsigned int key, const Action&, bool isRepeat);
+ bool ActionPressed(const Action&, const CKeySet& ks, bool isRepeat);
bool ActionReleased(const Action&);
-
+
bool HasLag() const;
+ volatile bool finishedLoading;
+
/// show GameEnd-window, calculate mouse movement etc.
void GameEnd(const std::vector<unsigned char>& winningAllyTeams);
-
enum GameDrawMode {
gameNotDrawing = 0,
gameNormalDraw = 1,
@@ -120,7 +117,6 @@ public:
bool showMTInfo;
/// Prevents spectator msgs from being seen by players
bool noSpectatorChat;
- volatile bool finishedLoading;
unsigned char gameID[16];
@@ -142,7 +138,7 @@ private:
void SendNetChat(std::string message, int destination = -1);
/// Format and display a chat message received over network
void HandleChatMsg(const ChatMessage& msg);
-
+
/// synced actions (received from server) go in here
void ActionReceived(const Action&, int playernum);
diff --git a/rts/Game/GameHelper.cpp b/rts/Game/GameHelper.cpp
index 404c9af..53b72de 100644
--- a/rts/Game/GameHelper.cpp
+++ b/rts/Game/GameHelper.cpp
@@ -829,7 +829,7 @@ public:
-void CGameHelper::GenerateWeaponTargets(const CWeapon* weapon, const CUnit* lastTargetUnit, std::multimap<float, CUnit*>& targets)
+void CGameHelper::GenerateWeaponTargets(const CWeapon* weapon, CUnit* lastTarget, std::multimap<float, CUnit*>& targets)
{
GML_RECMUTEX_LOCK(qnum); // GenerateTargets
@@ -845,7 +845,7 @@ void CGameHelper::GenerateWeaponTargets(const CWeapon* weapon, const CUnit* last
const std::vector<int>& quads = qf->GetQuads(pos, radius + (aHeight - std::max(0.f, readmap->minheight)) * heightMod);
- const int tempNum = gs->tempNum++;
+ int tempNum = gs->tempNum++;
typedef std::vector<int>::const_iterator VectorIt;
typedef std::list<CUnit*>::const_iterator ListIt;
@@ -893,16 +893,13 @@ void CGameHelper::GenerateWeaponTargets(const CWeapon* weapon, const CUnit* last
const float modRange = radius + (aHeight - targPos.y) * heightMod;
if ((pos - targPos).SqLength2D() <= modRange * modRange) {
- const float dist2D = (pos - targPos).Length2D();
- const float rangeMul = (dist2D * weapon->weaponDef->proximityPriority + modRange * 0.4f + 100.0f);
- const float damageMul = weapon->weaponDef->damages[targetUnit->armorType] * targetUnit->curArmorMultiple;
-
- targetPriority *= rangeMul;
+ float dist2d = (pos - targPos).Length2D();
+ targetPriority *= (dist2d * weapon->weaponDef->proximityPriority + modRange * 0.4f + 100.0f);
if (targetLOSState & LOS_INLOS) {
targetPriority *= (secDamage + targetUnit->health);
- if (targetUnit == lastTargetUnit) {
+ if (targetUnit == lastTarget) {
targetPriority *= weapon->avoidTarget ? 10.0f : 0.4f;
}
@@ -918,7 +915,9 @@ void CGameHelper::GenerateWeaponTargets(const CWeapon* weapon, const CUnit* last
}
if (targetLOSState & LOS_PREVLOS) {
- targetPriority /= (damageMul * targetUnit->power * (0.7f + gs->randFloat() * 0.6f));
+ targetPriority /=
+ weapon->weaponDef->damages[targetUnit->armorType] * targetUnit->curArmorMultiple *
+ targetUnit->power * (0.7f + gs->randFloat() * 0.6f);
if (targetUnit->category & weapon->badTargetCategory) {
targetPriority *= 100.0f;
@@ -945,6 +944,7 @@ void CGameHelper::GenerateWeaponTargets(const CWeapon* weapon, const CUnit* last
tracefile << "\n";
}
#endif
+
}
CUnit* CGameHelper::GetClosestUnit(const float3 &pos, float searchRadius)
diff --git a/rts/Game/GameHelper.h b/rts/Game/GameHelper.h
index b079d10..8d4845d 100644
--- a/rts/Game/GameHelper.h
+++ b/rts/Game/GameHelper.h
@@ -55,7 +55,7 @@ public:
CUnit* GetClosestFriendlyUnit(const float3& pos, float searchRadius, int searchAllyteam);
CUnit* GetClosestEnemyAircraft(const float3& pos, float searchRadius, int searchAllyteam);
- void GenerateWeaponTargets(const CWeapon* attacker, const CUnit* lastTarget, std::multimap<float, CUnit*>& targets);
+ void GenerateWeaponTargets(const CWeapon* attacker, CUnit* lastTarget, std::multimap<float, CUnit*>& targets);
float TraceRay(const float3& start, const float3& dir, float length, float power, const CUnit* owner, const CUnit*& hit, int collisionFlags = 0, const CFeature** hitFeature = NULL);
float GuiTraceRay(const float3& start, const float3& dir, float length, const CUnit*& hit, bool useRadar, const CUnit* exclude = NULL);
float GuiTraceRayFeature(const float3& start, const float3& dir, float length, const CFeature*& feature);
diff --git a/rts/Game/PreGame.cpp b/rts/Game/PreGame.cpp
index 69c4927..476d066 100644
--- a/rts/Game/PreGame.cpp
+++ b/rts/Game/PreGame.cpp
@@ -214,23 +214,19 @@ void CPreGame::UpdateClientNet()
std::string message;
pckt >> message;
logOutput.Print(message);
- handleerror(NULL, "Remote requested quit: " + message, "Quit message", MBF_OK | MBF_EXCL);
+ handleerror(NULL, message, "Quit message", MBF_OK | MBF_EXCL);
} catch (netcode::UnpackPacketException &e) {
logOutput.Print("Got invalid QuitMessage: %s", e.err.c_str());
}
break;
}
- case NETMSG_CREATE_NEWPLAYER: {
- // server will send this first if we're using mid-game join
- // feature, to let us know about ourself (we won't be in
- // gamedata), otherwise skip to gamedata
+ case NETMSG_CREATE_NEWPLAYER: { // server will send this first if we're using midgame join feature, to let us know about ourself (we won't be in gamedata), otherwise skip to gamedata
try {
netcode::UnpackPacket pckt(packet, 3);
unsigned char spectator, team, playerNum;
std::string name;
- // since the >> operator uses dest size to extract data from
- // the packet, we need to use temp variables of the same
- // size of the packet, before converting to dest variable
+ // since the >> operator uses dest size to extract data from the packet, we need to use temp variables
+ // of the same size of the packet, then convert to dest variable
pckt >> playerNum;
pckt >> spectator;
pckt >> team;
@@ -241,30 +237,22 @@ void CPreGame::UpdateClientNet()
player.spectator = spectator;
player.team = team;
player.playerNum = playerNum;
- // add ourself, to avoid crashing if our player num gets
- // queried we will receive the same message later, in the
- // game class, which is the global broadcast version
- // the global broadcast will overwrite the user with the
- // same values as here
+ // add ourself, to avoid crashing if our player num gets queried
+ // we'll receive the same message later, in the game class, which is the global broadcast version
+ // the global broadcast will overwrite the user with the same values as here
playerHandler->AddPlayer(player);
} catch (netcode::UnpackPacketException &e) {
logOutput.Print("Got invalid New player message: %s", e.err.c_str());
}
break;
}
- case NETMSG_GAMEDATA: {
- // server first sends this to let us know about teams, allyteams
- // etc.
- // (not if we are joining mid-game as extra players)
- // see NETMSG_SETPLAYERNUM
+ case NETMSG_GAMEDATA: { // server first ( not if we're joining midgame as extra players ) sends this to let us know about teams, allyteams etc.
if (gameSetup)
throw content_error("Duplicate game data received from server");
GameDataReceived(packet);
break;
}
- case NETMSG_SETPLAYERNUM: {
- // this is sent after NETMSG_GAMEDATA, to let us know which
- // playernum we have
+ case NETMSG_SETPLAYERNUM: { // this is sent afterwards to let us know which playernum we have
if (!gameSetup)
throw content_error("No game data received from server");
diff --git a/rts/Game/UI/GuiHandler.cpp b/rts/Game/UI/GuiHandler.cpp
index 0c298c2..87be01c 100644
--- a/rts/Game/UI/GuiHandler.cpp
+++ b/rts/Game/UI/GuiHandler.cpp
@@ -1412,7 +1412,8 @@ void CGuiHandler::RunCustomCommands(const std::vector<std::string>& cmds, bool r
Action action(copy);
if (!ProcessLocalActions(action)) {
- game->ActionPressed(-1, action, false /*isRepeat*/);
+ CKeySet ks;
+ game->ActionPressed(action, ks, false /*isRepeat*/);
}
keyInput->SetKeyState(SDLK_LALT, tmpAlt);
diff --git a/rts/Game/UnsyncedGameCommands.cpp b/rts/Game/UnsyncedGameCommands.cpp
index d7aae2a..ffb936b 100644
--- a/rts/Game/UnsyncedGameCommands.cpp
+++ b/rts/Game/UnsyncedGameCommands.cpp
@@ -15,7 +15,7 @@
#include "PlayerRoster.h"
#include "TimeProfiler.h"
#include "IVideoCapturing.h"
-#include "WordCompletion.h"
+#include "Game/UI/UnitTracker.h"
#ifdef _WIN32
# include "winerror.h"
#endif
@@ -55,7 +55,6 @@
#include "UI/SelectionKeyHandler.h"
#include "UI/ShareBox.h"
#include "UI/TooltipConsole.h"
-#include "UI/UnitTracker.h"
#include "UI/ProfileDrawer.h"
#include "System/ConfigHandler.h"
#include "System/EventHandler.h"
@@ -89,186 +88,9 @@ static std::vector<std::string> _local_strSpaceTokenize(const std::string& text)
}
-
-bool CGame::ProcessCommandText(unsigned int key, const std::string& command) {
- if (command.size() <= 2)
- return false;
-
- if ((command[0] == '/') && (command[1] != '/')) {
- const string actionLine = command.substr(1); // strip the '/'
-
- Action fakeAction(actionLine);
- ActionPressed(key, fakeAction, false);
- return true;
- }
-
- return false;
-}
-
-bool CGame::ProcessKeyPressAction(unsigned int key, const Action& action) {
- if (action.command == "edit_return") {
- userWriting = false;
- writingPos = 0;
-
- if (key == SDLK_RETURN) {
- // prevent game start when host enters a chat message
- keyInput->SetKeyState(key, 0);
- }
- if (chatting) {
- string command;
-
- if ((userInput.find_first_of("aAsS") == 0) && (userInput[1] == ':')) {
- command = userInput.substr(2);
- } else {
- command = userInput;
- }
-
- if (ProcessCommandText(key, command)) {
- // execute an action
- consoleHistory->AddLine(command);
- logOutput.Print(command);
-
- chatting = false;
- userInput = "";
- writingPos = 0;
- }
- }
- return true;
- }
- else if ((action.command == "edit_escape") && (chatting || inMapDrawer->wantLabel)) {
- if (chatting) {
- consoleHistory->AddLine(userInput);
- }
- userWriting = false;
- chatting = false;
- inMapDrawer->wantLabel = false;
- userInput = "";
- writingPos = 0;
- return true;
- }
- else if (action.command == "edit_complete") {
- string head = userInput.substr(0, writingPos);
- string tail = userInput.substr(writingPos);
- const vector<string> &partials = wordCompletion->Complete(head);
- userInput = head + tail;
- writingPos = (int)head.length();
-
- if (!partials.empty()) {
- string msg;
- for (unsigned int i = 0; i < partials.size(); i++) {
- msg += " ";
- msg += partials[i];
- }
- logOutput.Print(msg);
- }
- return true;
- }
- else if (action.command == "chatswitchall") {
- if ((userInput.find_first_of("aAsS") == 0) && (userInput[1] == ':')) {
- userInput = userInput.substr(2);
- writingPos = std::max(0, writingPos - 2);
- }
-
- userInputPrefix = "";
- return true;
- }
- else if (action.command == "chatswitchally") {
- if ((userInput.find_first_of("aAsS") == 0) && (userInput[1] == ':')) {
- userInput[0] = 'a';
- } else {
- userInput = "a:" + userInput;
- writingPos += 2;
- }
-
- userInputPrefix = "a:";
- return true;
- }
- else if (action.command == "chatswitchspec") {
- if ((userInput.find_first_of("aAsS") == 0) && (userInput[1] == ':')) {
- userInput[0] = 's';
- } else {
- userInput = "s:" + userInput;
- writingPos += 2;
- }
-
- userInputPrefix = "s:";
- return true;
- }
- else if (action.command == "pastetext") {
- if (!action.extra.empty()) {
- userInput.insert(writingPos, action.extra);
- writingPos += action.extra.length();
- } else {
- PasteClipboard();
- }
- return true;
- }
-
- else if (action.command == "edit_backspace") {
- if (!userInput.empty() && (writingPos > 0)) {
- userInput.erase(writingPos - 1, 1);
- writingPos--;
- }
- return true;
- }
- else if (action.command == "edit_delete") {
- if (!userInput.empty() && (writingPos < (int)userInput.size())) {
- userInput.erase(writingPos, 1);
- }
- return true;
- }
- else if (action.command == "edit_home") {
- writingPos = 0;
- return true;
- }
- else if (action.command == "edit_end") {
- writingPos = (int)userInput.length();
- return true;
- }
- else if (action.command == "edit_prev_char") {
- writingPos = std::max(0, std::min((int)userInput.length(), writingPos - 1));
- return true;
- }
- else if (action.command == "edit_next_char") {
- writingPos = std::max(0, std::min((int)userInput.length(), writingPos + 1));
- return true;
- }
- else if (action.command == "edit_prev_word") {
- // prev word
- const char* s = userInput.c_str();
- int p = writingPos;
- while ((p > 0) && !isalnum(s[p - 1])) { p--; }
- while ((p > 0) && isalnum(s[p - 1])) { p--; }
- writingPos = p;
- return true;
- }
- else if (action.command == "edit_next_word") {
- const int len = (int)userInput.length();
- const char* s = userInput.c_str();
- int p = writingPos;
- while ((p < len) && !isalnum(s[p])) { p++; }
- while ((p < len) && isalnum(s[p])) { p++; }
- writingPos = p;
- return true;
- }
- else if ((action.command == "edit_prev_line") && chatting) {
- userInput = consoleHistory->PrevLine(userInput);
- writingPos = (int)userInput.length();
- return true;
- }
- else if ((action.command == "edit_next_line") && chatting) {
- userInput = consoleHistory->NextLine(userInput);
- writingPos = (int)userInput.length();
- return true;
- }
-
- return false;
-}
-
-
-
// FOR UNSYNCED MESSAGES
-bool CGame::ActionPressed(unsigned int key, const Action& action, bool isRepeat)
+bool CGame::ActionPressed(const Action& action,
+ const CKeySet& ks, bool isRepeat)
{
// we may need these later
CBaseGroundDrawer* gd = readmap->GetGroundDrawer();
@@ -409,7 +231,7 @@ bool CGame::ActionPressed(unsigned int key, const Action& action, bool isRepeat)
if (pos.x >= 0) {
inMapDrawer->keyPressed = false;
inMapDrawer->PromptLabel(pos);
- if ((key >= SDLK_SPACE) && (key <= SDLK_DELETE)) {
+ if ((ks.Key() >= SDLK_SPACE) && (ks.Key() <= SDLK_DELETE)) {
ignoreNextChar=true;
}
}
@@ -803,7 +625,7 @@ bool CGame::ActionPressed(unsigned int key, const Action& action, bool isRepeat)
else if (((cmd == "chat") || (cmd == "chatall") ||
(cmd == "chatally") || (cmd == "chatspec")) &&
// if chat is bound to enter and we're waiting for user to press enter to start game, ignore.
- (key != SDLK_RETURN || playing || !keyInput->IsKeyPressed(SDLK_LCTRL))) {
+ (ks.Key() != SDLK_RETURN || playing || !keyInput->IsKeyPressed(SDLK_LCTRL))) {
if (cmd == "chatall") { userInputPrefix = ""; }
if (cmd == "chatally") { userInputPrefix = "a:"; }
@@ -814,7 +636,7 @@ bool CGame::ActionPressed(unsigned int key, const Action& action, bool isRepeat)
writingPos = (int)userInput.length();
chatting = true;
- if (key != SDLK_RETURN) {
+ if (ks.Key() != SDLK_RETURN) {
ignoreNextChar = true;
}
@@ -1646,3 +1468,5 @@ bool CGame::ActionPressed(unsigned int key, const Action& action, bool isRepeat)
return true;
}
+
+
diff --git a/rts/Rendering/Env/AdvSky.cpp b/rts/Rendering/Env/AdvSky.cpp
index 08393fe..680fa0f 100644
--- a/rts/Rendering/Env/AdvSky.cpp
+++ b/rts/Rendering/Env/AdvSky.cpp
@@ -46,7 +46,6 @@ CAdvSky::CAdvSky()
domeWidth = sin(2*PI/32)*400*1.7f;
UpdateSkyDir();
- InitSun();
UpdateSunDir();
for(int a=0;a<CLOUD_DETAIL;a++)
@@ -65,15 +64,11 @@ CAdvSky::CAdvSky()
CreateClouds();
dynamicSky = configHandler->Get("DynamicSky", false);
+ InitSun();
oldCoverBaseX=-5;
cloudFP = LoadFragmentProgram("ARB/clouds.fp");
- CreateSkyDomeList();
-}
-
-void CAdvSky::CreateSkyDomeList()
-{
glGetError();
skyDomeList = glGenLists(1);
glNewList(skyDomeList, GL_COMPILE);
@@ -665,7 +660,7 @@ void CAdvSky::InitSun()
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
// gluBuild2DMipmaps(GL_TEXTURE_2D,1 ,32, 2, GL_ALPHA, GL_UNSIGNED_BYTE, mem);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE ,32, 4, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, mem);
+ glTexImage2D(GL_TEXTURE_2D,0,GL_LUMINANCE ,32, 4,0, GL_LUMINANCE, GL_UNSIGNED_BYTE, mem);
delete [] mem;
}
diff --git a/rts/Rendering/Env/AdvSky.h b/rts/Rendering/Env/AdvSky.h
index f963437..5686ce9 100644
--- a/rts/Rendering/Env/AdvSky.h
+++ b/rts/Rendering/Env/AdvSky.h
@@ -21,7 +21,6 @@ public:
void UpdateSkyTexture();
private:
- void CreateSkyDomeList();
void InitSun();
void UpdateSunFlare();
void CreateCover(int baseX, int baseY, float* buf);
diff --git a/rts/Rendering/Env/BaseTreeDrawer.cpp b/rts/Rendering/Env/BaseTreeDrawer.cpp
index bcfcd20..31ebe22 100644
--- a/rts/Rendering/Env/BaseTreeDrawer.cpp
+++ b/rts/Rendering/Env/BaseTreeDrawer.cpp
@@ -7,7 +7,6 @@
#include "BasicTreeDrawer.h"
#include "AdvTreeDrawer.h"
#include "Game/Camera.h"
-#include "Rendering/GlobalRendering.h"
#include "Sim/Features/FeatureHandler.h"
#include "Sim/Features/Feature.h"
#include "Sim/Misc/GlobalConstants.h"
@@ -83,8 +82,7 @@ void CBaseTreeDrawer::DrawShadowPass()
void CBaseTreeDrawer::Draw(bool drawReflection)
{
- const float maxDistance = CGlobalRendering::MAX_VIEW_RANGE / (SQUARE_SIZE * TREE_SQUARE_SIZE);
- const float treeDistance = Clamp(baseTreeDistance, 1.0f, maxDistance);
+ const float treeDistance = Clamp(baseTreeDistance, 1.0f, (float)MAX_VIEW_RANGE / (SQUARE_SIZE * TREE_SQUARE_SIZE));
Draw(treeDistance, drawReflection);
}
diff --git a/rts/Rendering/Env/BasicSky.cpp b/rts/Rendering/Env/BasicSky.cpp
index 67621f5..10b2b3e 100644
--- a/rts/Rendering/Env/BasicSky.cpp
+++ b/rts/Rendering/Env/BasicSky.cpp
@@ -48,7 +48,6 @@ CBasicSky::CBasicSky()
domeWidth=sin(PI/16)*400*1.7f;
UpdateSkyDir();
- InitSun();
UpdateSunDir();
cloudDensity = 0.25f + mapInfo->atmosphere.cloudDensity * 0.5f;
@@ -67,9 +66,8 @@ CBasicSky::CBasicSky()
CreateClouds();
dynamicSky = configHandler->Get("DynamicSky", false);
+ InitSun();
oldCoverBaseX=-5;
-
- CreateSkyDomeList();
}
void CBasicSky::CreateSkyDomeList()
@@ -514,7 +512,7 @@ void CBasicSky::DrawSun()
glDisable(GL_DEPTH_TEST);
glDisable(GL_ALPHA_TEST);
- static unsigned char buf[32];
+ static unsigned char buf[128];
glEnable(GL_TEXTURE_2D);
float3 modCamera=sundir1*camera->pos.x+sundir2*camera->pos.z;
@@ -538,6 +536,7 @@ void CBasicSky::DrawSun()
}
float mid=0;
+ unsigned char *bf=buf+32, *bf2=buf+64;
for(int x=0;x<32;++x){
float cx1=(*cvs++)*(1-fx)+(*cvs1++)*fx;
float cx2=(*cvs2++)*(1-fx)+(*cvs3++)*fx;
@@ -546,6 +545,9 @@ void CBasicSky::DrawSun()
if(cover>127.5f)
cover=127.5f;
mid+=cover;
+
+ (*bf++)=(unsigned char)(255-cover*2);
+ (*bf2++)=(unsigned char)(128-cover);
}
mid*=1.0f/32;
for(int x=0;x<32;++x){
@@ -553,7 +555,7 @@ void CBasicSky::DrawSun()
}
glBindTexture(GL_TEXTURE_2D, sunFlareTex);
- glTexSubImage2D(GL_TEXTURE_2D,0,0,0,32,1,GL_LUMINANCE,GL_UNSIGNED_BYTE,buf);
+ glTexSubImage2D(GL_TEXTURE_2D,0,0,0,32,3,GL_LUMINANCE,GL_UNSIGNED_BYTE,buf);
const float si = skyLight->GetLightIntensity();
const float3 sc = sunColor * si;
@@ -584,9 +586,9 @@ void CBasicSky::UpdateSunFlare() {
float dx=sin(x*2*PI/256.0f);
float dy=cos(x*2*PI/256.0f);
- glTexCoord2f(x/256.0f,0.25f);
+ glTexCoord2f(x/256.0f,0.125f);
glVertexf3(modSunDir*5+ldir*dx*0.0014f+udir*dy*0.0014f);
- glTexCoord2f(x/256.0f,0.75f);
+ glTexCoord2f(x/256.0f,0.875f);
glVertexf3(modSunDir*5+ldir*dx*4+udir*dy*4);
}
glEnd();
@@ -621,7 +623,7 @@ void CBasicSky::InitSun()
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
glBuildMipmaps(GL_TEXTURE_2D,GL_RGBA8 ,128, 128, GL_RGBA, GL_UNSIGNED_BYTE, mem);
- for(int y=0;y<2;++y){
+ for(int y=0;y<4;++y){
for(int x=0;x<32;++x){
if(y==0 && x%2)
mem[(y*32+x)]=255;
@@ -635,7 +637,7 @@ void CBasicSky::InitSun()
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE ,32, 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, mem);
+ glTexImage2D(GL_TEXTURE_2D,0, GL_LUMINANCE, 32, 4, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, mem);
delete[] mem;
}
@@ -793,13 +795,14 @@ void CBasicSky::UpdateTexPartDot3(int x, int y, unsigned char (*texp)[4]) {
const float sunInt = skyLight->GetLightIntensity();
const float sunDist = acos(dir.dot(skyLight->GetLightDir())) * 50;
- const float sunMod = sunInt * (0.3f / math::sqrt(sunDist) + 2.0f / sunDist);
+ const float sunMod = sunInt * (0.3f / math::sqrt(sunDist) + 3.0f / (1 + sunDist));
const float green = std::min(1.0f, (0.55f + sunMod));
+ const float blue = 203 - sunInt * (40.0f / (3 + sunDist));
texp[x][0] = (unsigned char) (sunInt * (255 - std::min(255.0f, sunDist))); // sun on borders
texp[x][1] = (unsigned char) (green * 255); // sun light through
- texp[x][2] = (unsigned char) 203; // ambient
+ texp[x][2] = (unsigned char) blue; // ambient
texp[x][3] = 255;
}
diff --git a/rts/Rendering/FarTextureHandler.cpp b/rts/Rendering/FarTextureHandler.cpp
old mode 100644
new mode 100755
index 3a7978a..74f20f4
--- a/rts/Rendering/FarTextureHandler.cpp
+++ b/rts/Rendering/FarTextureHandler.cpp
@@ -181,7 +181,7 @@ void CFarTextureHandler::CreateFarTexture(const CSolidObject* obj)
unitDrawer->SetupForUnitDrawing();
unitDrawer->GetOpaqueModelRenderer(model->type)->PushRenderState();
- if (model->type == MODELTYPE_S3O || model->type == MODELTYPE_OBJ) {
+ if (model->type == MODELTYPE_S3O || model->type == MODELTYPE_OBJ || model->type == MODELTYPE_ASS) {
// FIXME for some strange reason we need to invert the culling, why?
if (model->type == MODELTYPE_S3O) {
glCullFace(GL_FRONT);
diff --git a/rts/Rendering/FeatureDrawer.cpp b/rts/Rendering/FeatureDrawer.cpp
old mode 100644
new mode 100755
index 4385a71..b88eab3
--- a/rts/Rendering/FeatureDrawer.cpp
+++ b/rts/Rendering/FeatureDrawer.cpp
@@ -229,7 +229,7 @@ void CFeatureDrawer::DrawOpaqueFeatures(int modelType)
FeatureSet::iterator featureSetIt;
for (featureBinIt = featureBin.begin(); featureBinIt != featureBin.end(); ++featureBinIt) {
- if (modelType == MODELTYPE_S3O || modelType == MODELTYPE_OBJ) {
+ if (modelType == MODELTYPE_S3O || modelType == MODELTYPE_OBJ || modelType == MODELTYPE_ASS) {
texturehandlerS3O->SetS3oTexture(featureBinIt->first);
}
@@ -371,7 +371,7 @@ void CFeatureDrawer::DrawFadeFeaturesHelper(int modelType) {
FeatureRenderBin& featureBin = cloakedModelRenderers[modelType]->GetFeatureBinMutable();
for (FeatureRenderBinIt it = featureBin.begin(); it != featureBin.end(); ++it) {
- if (modelType == MODELTYPE_S3O || modelType == MODELTYPE_OBJ) {
+ if (modelType == MODELTYPE_S3O || modelType == MODELTYPE_OBJ || modelType == MODELTYPE_ASS) {
texturehandlerS3O->SetS3oTexture(it->first);
}
diff --git a/rts/Rendering/GlobalRendering.cpp b/rts/Rendering/GlobalRendering.cpp
index 60bd337..86d328b 100644
--- a/rts/Rendering/GlobalRendering.cpp
+++ b/rts/Rendering/GlobalRendering.cpp
@@ -22,8 +22,6 @@
*/
CGlobalRendering* globalRendering;
-const float CGlobalRendering::MAX_VIEW_RANGE = 8000.0f;
-const float CGlobalRendering::NEAR_PLANE = 2.8f;
CR_BIND(CGlobalRendering, );
diff --git a/rts/Rendering/GlobalRendering.h b/rts/Rendering/GlobalRendering.h
index 38525b0..e60ba46 100644
--- a/rts/Rendering/GlobalRendering.h
+++ b/rts/Rendering/GlobalRendering.h
@@ -4,6 +4,8 @@
#define _GLOBAL_RENDERING_H
#include "System/creg/creg_cond.h"
+#include "System/float4.h"
+#include "System/Matrix44f.h"
/**
* @brief Globally accessible unsynced, rendering related data
@@ -180,18 +182,6 @@ public:
* @brief full-screen or windowed rendering
*/
bool fullScreen;
-
-
-
- /**
- * @brief max view range in elmos
- */
- static const float MAX_VIEW_RANGE;
-
- /**
- * @brief near z-plane distance in elmos
- */
- static const float NEAR_PLANE;
};
extern CGlobalRendering* globalRendering;
diff --git a/rts/Rendering/Models/3DModel.cpp b/rts/Rendering/Models/3DModel.cpp
old mode 100644
new mode 100755
index 5c3d98d..02df7b7
--- a/rts/Rendering/Models/3DModel.cpp
+++ b/rts/Rendering/Models/3DModel.cpp
@@ -18,6 +18,18 @@
//////////////////////////////////////////////////////////////////////
+// S3DModel
+//
+
+S3DModelPiece* S3DModel::FindPiece( std::string name )
+{
+ const ModelPieceMap::const_iterator it = pieces.find(name);
+ if (it != pieces.end()) return it->second;
+ return NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////
// S3DModelPiece
//
diff --git a/rts/Rendering/Models/3DModel.h b/rts/Rendering/Models/3DModel.h
old mode 100644
new mode 100755
index ba577b7..0501a41
--- a/rts/Rendering/Models/3DModel.h
+++ b/rts/Rendering/Models/3DModel.h
@@ -5,23 +5,26 @@
#include <vector>
#include <string>
-
+#include <set>
+#include <map>
#include "System/Matrix44f.h"
-
const int
MODELTYPE_3DO = 0,
MODELTYPE_S3O = 1,
MODELTYPE_OBJ = 2,
- MODELTYPE_OTHER = 3;
+ MODELTYPE_ASS = 3, // Model loaded by Assimp library
+ MODELTYPE_OTHER = 4; // For future use. Still used in some parts of code.
struct CollisionVolume;
struct S3DModel;
struct S3DModelPiece;
struct LocalModel;
struct LocalModelPiece;
+struct aiScene;
+typedef std::map<std::string, S3DModelPiece*> ModelPieceMap;
struct S3DModelPiece {
S3DModelPiece(): type(-1) {
@@ -53,8 +56,10 @@ struct S3DModelPiece {
std::string name;
+ std::string parentName;
std::vector<S3DModelPiece*> childs;
+ S3DModel* model;
S3DModelPiece* parent;
CollisionVolume* colvol;
@@ -68,23 +73,32 @@ struct S3DModelPiece {
float3 maxs;
float3 offset; // wrt. parent
float3 goffset; // wrt. root
+ float3 rot;
+ float3 scale;
};
struct S3DModel
{
S3DModel(): id(-1), type(-1), textureType(-1) {
- numPieces = 0;
-
- radius = 0.0f;
- height = 0.0f;
-
- rootPiece = NULL;
+ height = 0.0f;
+ radius = 0.0f;
+ relMidPos = float3(0.0f, 0.0f, 0.0f);
+ mins = float3(10000.0f, 10000.0f, 10000.0f);
+ maxs = float3(-10000.0f, -10000.0f, -10000.0f);
+ tex1 = "default.png";
+ tex2 = "";
+ flipTexY = false;
+ invertTexAlpha = false;
+ numPieces = 0;
+ rootPiece = NULL;
+ scene = NULL;
}
S3DModelPiece* GetRootPiece() { return rootPiece; }
void SetRootPiece(S3DModelPiece* p) { rootPiece = p; }
void DrawStatic() const { rootPiece->DrawStatic(); }
+ S3DModelPiece* FindPiece( std::string name );
std::string name;
std::string tex1;
@@ -93,8 +107,9 @@ struct S3DModel
int id; //! unsynced ID, starting with 1
int type; //! MODELTYPE_*
int textureType; //! FIXME: MAKE S3O ONLY (0 = 3DO, otherwise S3O or OBJ)
+ bool flipTexY; //! Turn both textures upside down before use
+ bool invertTexAlpha; //! Invert teamcolor alpha channel in S3O texture 1
- int numPieces;
float radius;
float height;
@@ -102,7 +117,10 @@ struct S3DModel
float3 maxs;
float3 relMidPos;
- S3DModelPiece* rootPiece;
+ int numPieces;
+ S3DModelPiece* rootPiece; //! The piece at the base of the model hierarchy
+ ModelPieceMap pieces; //! Lookup table for pieces by name
+ const aiScene* scene; //! Assimp scene containing all loaded model data. NULL for S30/3DO.
};
diff --git a/rts/Rendering/Models/3DModelLog.h b/rts/Rendering/Models/3DModelLog.h
new file mode 100644
index 0000000..c1b38e2
--- /dev/null
+++ b/rts/Rendering/Models/3DModelLog.h
@@ -0,0 +1,14 @@
+/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
+
+#ifndef _3DMODELLOG_H_
+#define _3DMODELLOG_H_
+
+#include "System/LogOutput.h"
+
+// Enabling the "Model" and "Piece" log subsystems will help debug model loading. "Model-detail" is extremely verbose.
+static CLogSubsystem LOG_MODEL("Model");
+static CLogSubsystem LOG_MODEL_DETAIL("Model-detail");
+static CLogSubsystem LOG_PIECE("Piece");
+static CLogSubsystem LOG_PIECE_DETAIL("Piece-detail");
+
+#endif // _3DMODELLOG_H_
diff --git a/rts/Rendering/Models/AssIO.cpp b/rts/Rendering/Models/AssIO.cpp
new file mode 100644
index 0000000..9a2a1cb
--- /dev/null
+++ b/rts/Rendering/Models/AssIO.cpp
@@ -0,0 +1,96 @@
+#include "StdAfx.h"
+
+#include <string>
+
+#include "AssIO.h"
+
+#include "FileSystem/FileHandler.h"
+
+AssVFSStream::AssVFSStream(const std::string& pFile, const std::string& pMode)
+{
+ file = new CFileHandler(pFile, pMode);
+}
+
+AssVFSStream::~AssVFSStream(void)
+{
+ delete file;
+}
+
+size_t AssVFSStream::Read( void* pvBuffer, size_t pSize, size_t pCount)
+{
+ // Spring VFS only supports reading chars. Need to convert.
+ int length = pSize * pCount;
+ return file->Read(pvBuffer, length);
+}
+
+size_t AssVFSStream::Write( const void* pvBuffer, size_t pSize, size_t pCount)
+{
+ // FAKE. Shouldn't need to write back to VFS
+ return pSize * pCount;
+}
+
+aiReturn AssVFSStream::Seek( size_t pOffset, aiOrigin pOrigin)
+{
+ switch(pOrigin){
+ case aiOrigin_SET: // from start of file
+ if ( pOffset >= file->FileSize() ) return AI_FAILURE;
+ file->Seek( pOffset, std::ios_base::beg );
+ break;
+ case aiOrigin_CUR: // from current position in file
+ if ( pOffset >= ( file->FileSize() + file->GetPos() ) ) return AI_FAILURE;
+ file->Seek( pOffset, std::ios_base::cur );
+ break;
+ case aiOrigin_END: // reverse from end of file
+ if ( pOffset >= file->FileSize() ) return AI_FAILURE;
+ file->Seek( pOffset, std::ios_base::end );
+ break;
+ }
+ return AI_SUCCESS;
+}
+
+size_t AssVFSStream::Tell() const
+{
+ return file->GetPos();
+}
+
+
+size_t AssVFSStream::FileSize() const
+{
+ int filesize = file->FileSize();
+ if ( filesize < 0 ) filesize = 0;
+ return filesize;
+}
+
+void AssVFSStream::Flush () // FAKE
+{
+}
+
+
+// Check whether a specific file exists
+bool AssVFSSystem::Exists( const char* pFile) const
+{
+ CFileHandler file(pFile);
+ return file.FileExists();
+}
+
+// Get the path delimiter character we'd like to get
+char AssVFSSystem::getOsSeparator() const
+{
+ return '/';
+}
+
+bool AssVFSSystem::ComparePaths (const std::string& one, const std::string& second) const
+{
+ return one == second; // too naive? probably should convert to absolute paths
+}
+
+// open a custom stream
+Assimp::IOStream* AssVFSSystem::Open( const char* pFile, const char* pMode)
+{
+ return new AssVFSStream( pFile, pMode );
+}
+
+void AssVFSSystem::Close( Assimp::IOStream* pFile)
+{
+ delete pFile;
+}
diff --git a/rts/Rendering/Models/AssIO.h b/rts/Rendering/Models/AssIO.h
new file mode 100644
index 0000000..7b34efa
--- /dev/null
+++ b/rts/Rendering/Models/AssIO.h
@@ -0,0 +1,52 @@
+#ifndef ASSIO_H
+#define ASSIO_H
+
+#include "IOStream.h"
+#include "IOSystem.h"
+class CFileHandler;
+
+// Custom implementation of Assimp IOStream to support Spring's VFS
+// Required because Assimp models often need to load textures from other files
+
+class AssVFSStream : public Assimp::IOStream
+{
+ friend class AssVFSSystem;
+ CFileHandler* file;
+
+protected:
+ // Constructor protected for private usage by AssVFSSystem
+ AssVFSStream(const std::string& pFile, const std::string& pMode);
+
+public:
+ ~AssVFSStream(void);
+ size_t Read( void* pvBuffer, size_t pSize, size_t pCount);
+ size_t Write( const void* pvBuffer, size_t pSize, size_t pCount);
+ aiReturn Seek( size_t pOffset, aiOrigin pOrigin);
+ size_t Tell() const;
+ size_t FileSize() const;
+ void Flush ();
+};
+
+
+// Spring VFS Filesystem Wrapper for Assimp
+
+class AssVFSSystem : public Assimp::IOSystem
+{
+public:
+ AssVFSSystem() { }
+ ~AssVFSSystem() { }
+
+ // Check whether a specific file exists
+ bool Exists( const char* pFile) const;
+
+ // Get the path delimiter character we'd like to get
+ char getOsSeparator() const;
+ bool ComparePaths (const std::string& one, const std::string& second) const;
+
+ // open a custom stream
+ Assimp::IOStream* Open( const char* pFile, const char* pMode = "rb" );
+
+ void Close( Assimp::IOStream* pFile);
+};
+
+#endif
diff --git a/rts/Rendering/Models/AssParser.cpp b/rts/Rendering/Models/AssParser.cpp
new file mode 100755
index 0000000..2678a01
--- /dev/null
+++ b/rts/Rendering/Models/AssParser.cpp
@@ -0,0 +1,565 @@
+// AssParser.cpp: implementation of the CAssParser class. Reads 3D formats supported by Assimp lib.
+//
+//////////////////////////////////////////////////////////////////////
+//#include "StdAfx.h"
+
+#include "Util.h"
+#include "LogOutput.h"
+#include "Platform/errorhandler.h"
+#include "System/Exceptions.h"
+#include "Sim/Misc/CollisionVolume.h"
+#include "FileSystem/FileHandler.h"
+#include "Lua/LuaParser.h"
+#include "3DModel.h"
+#include "3DModelLog.h"
+#include "S3OParser.h"
+#include "AssIO.h"
+#include "AssParser.h"
+
+#include "assimp.hpp"
+#include "aiDefines.h"
+#include "aiTypes.h"
+#include "aiScene.h"
+#include "aiPostProcess.h"
+#include "DefaultLogger.h"
+#include "Rendering/Textures/S3OTextureHandler.h"
+
+#define IS_QNAN(f) (f != f)
+#define DEGTORAD 0.0174532925
+
+// triangulate guarantees the most complex mesh is a triangle
+// sortbytype ensure only 1 type of primitive type per mesh is used
+#define ASS_POSTPROCESS_OPTIONS \
+ aiProcess_RemoveComponent | \
+ aiProcess_FindInvalidData | \
+ aiProcess_CalcTangentSpace | \
+ aiProcess_GenSmoothNormals | \
+ aiProcess_SplitLargeMeshes | \
+ aiProcess_Triangulate | \
+ aiProcess_GenUVCoords | \
+ aiProcess_SortByPType | \
+ aiProcess_JoinIdenticalVertices
+
+//aiProcess_ImproveCacheLocality
+
+// Convert Assimp quaternion to radians around x, y and z
+float3 QuaternionToRadianAngles( aiQuaternion q1 )
+{
+ float sqw = q1.w*q1.w;
+ float sqx = q1.x*q1.x;
+ float sqy = q1.y*q1.y;
+ float sqz = q1.z*q1.z;
+ float unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor
+ float test = q1.x*q1.y + q1.z*q1.w;
+
+ float3 result(0.0f, 0.0f, 0.0f);
+
+ if (test > 0.499f * unit) { // singularity at north pole
+ result.x = 2 * atan2(q1.x,q1.w);
+ result.y = PI/2;
+ } else if (test < -0.499f * unit) { // singularity at south pole
+ result.x = -2 * atan2(q1.x,q1.w);
+ result.y = -PI/2;
+ } else {
+ result.x = atan2(2*q1.y*q1.w-2*q1.x*q1.z , sqx - sqy - sqz + sqw);
+ result.y = asin(2*test/unit);
+ result.z = atan2(2*q1.x*q1.w-2*q1.y*q1.z , -sqx + sqy - sqz + sqw);
+ }
+ return result;
+}
+
+// Convert float3 rotations in degrees to radians
+void DegreesToRadianAngles( float3& angles )
+{
+ angles.x *= DEGTORAD;
+ angles.y *= DEGTORAD;
+ angles.z *= DEGTORAD;
+}
+
+class AssLogStream : public Assimp::LogStream
+{
+public:
+ AssLogStream() {}
+ ~AssLogStream() {}
+ void write(const char* message)
+ {
+ logOutput.Print (LOG_MODEL_DETAIL, "Assimp: %s", message);
+ }
+};
+
+
+
+S3DModel* CAssParser::Load(const std::string& modelFileName)
+{
+ logOutput.Print (LOG_MODEL, "Loading model: %s\n", modelFileName.c_str() );
+ std::string modelPath = modelFileName.substr(0, modelFileName.find_last_of('/'));
+ std::string modelFileNameNoPath = modelFileName.substr(modelPath.length()+1, modelFileName.length());
+ std::string modelName = modelFileNameNoPath.substr(0, modelFileNameNoPath.find_last_of('.'));
+ std::string modelExt = modelFileNameNoPath.substr(modelFileNameNoPath.find_last_of('.'), modelFileName.length());
+
+ // LOAD METADATA
+ // Load the lua metafile. This contains properties unique to Spring models and must return a table
+ std::string metaFileName = modelFileName + ".lua";
+ CFileHandler* metaFile = new CFileHandler(metaFileName);
+ if (!metaFile->FileExists()) {
+ // Try again without the model file extension
+ metaFileName = modelPath + '/' + modelName + ".lua";
+ metaFile = new CFileHandler(metaFileName);
+ }
+ LuaParser metaFileParser(metaFileName, SPRING_VFS_MOD_BASE, SPRING_VFS_ZIP);
+ if (!metaFileParser.Execute()) {
+ if (!metaFile->FileExists()) {
+ logOutput.Print(LOG_MODEL, "No meta-file '%s'. Using defaults.", metaFileName.c_str());
+ } else {
+ logOutput.Print(LOG_MODEL, "ERROR in '%s': %s. Using defaults.", metaFileName.c_str(), metaFileParser.GetErrorLog().c_str());
+ }
+ }
+ // Get the (root-level) model table
+ const LuaTable& metaTable = metaFileParser.GetRoot();
+ if (metaTable.IsValid()) logOutput.Print(LOG_MODEL, "Found valid model metadata in '%s'", metaFileName.c_str());
+
+
+ // LOAD MODEL DATA
+ // Create a model importer instance
+ Assimp::Importer importer;
+
+ // Create a logger for debugging model loading issues
+ Assimp::DefaultLogger::create("",Assimp::Logger::VERBOSE);
+ const unsigned int severity = Assimp::Logger::DEBUGGING|Assimp::Logger::INFO|Assimp::Logger::ERR|Assimp::Logger::WARN;
+ Assimp::DefaultLogger::get()->attachStream( new AssLogStream(), severity );
+
+ // Give the importer an IO class that handles Spring's VFS
+ importer.SetIOHandler( new AssVFSSystem() );
+
+ // Speed-up processing by skipping things we don't need
+ importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS, aiComponent_CAMERAS|aiComponent_LIGHTS|aiComponent_TEXTURES|aiComponent_ANIMATIONS);
+
+ // Read the model file to build a scene object
+ logOutput.Print(LOG_MODEL, "Importing model file: %s\n", modelFileName.c_str() );
+ const aiScene* scene = importer.ReadFile( modelFileName, ASS_POSTPROCESS_OPTIONS );
+ if (scene != NULL) {
+ logOutput.Print(LOG_MODEL, "Processing scene for model: %s (%d meshes / %d materials / %d textures)", modelFileName.c_str(), scene->mNumMeshes, scene->mNumMaterials, scene->mNumTextures );
+ } else {
+ logOutput.Print (LOG_MODEL, "Model Import Error: %s\n", importer.GetErrorString());
+ }
+
+ S3DModel* model = new S3DModel;
+ model->name = modelFileName;
+ model->type = MODELTYPE_ASS;
+ model->numPieces = 0;
+ model->scene = scene;
+ //model->meta = &metaTable;
+
+ // Assign textures
+ // The S3O texture handler uses two textures.
+ // The first contains diffuse color (RGB) and teamcolor (A)
+ // The second contains glow (R), reflectivity (G) and 1-bit Alpha (A).
+ if (metaTable.KeyExists("tex1")) {
+ model->tex1 = metaTable.GetString("tex1", "default.png");
+ } else {
+ // Search for a texture
+ std::vector<std::string> files = CFileHandler::FindFiles("unittextures/", modelName + ".*");
+ for(std::vector<std::string>::iterator fi = files.begin(); fi != files.end(); ++fi) {
+ std::string texPath = std::string(*fi);
+ model->tex1 = texPath.substr(texPath.find('/')+1, texPath.length());
+ break; // there can be only one!
+ }
+ }
+ if (metaTable.KeyExists("tex2")) {
+ model->tex2 = metaTable.GetString("tex2", "");
+ } else {
+ // Search for a texture
+ std::vector<std::string> files = CFileHandler::FindFiles("unittextures/", modelName + "2.*");
+ for(std::vector<std::string>::iterator fi = files.begin(); fi != files.end(); ++fi) {
+ std::string texPath = std::string(*fi);
+ model->tex2 = texPath.substr(texPath.find('/')+1, texPath.length());
+ break; // there can be only one!
+ }
+ }
+ model->flipTexY = metaTable.GetBool("fliptextures", true); // Flip texture upside down
+ model->invertTexAlpha = metaTable.GetBool("invertteamcolor", true); // Reverse teamcolor levels
+
+ // Load textures
+ logOutput.Print(LOG_MODEL, "Loading textures. Tex1: '%s' Tex2: '%s'", model->tex1.c_str(), model->tex2.c_str());
+ texturehandlerS3O->LoadS3OTexture(model);
+
+ // Load all pieces in the model
+ logOutput.Print(LOG_MODEL, "Loading pieces from root node '%s'", scene->mRootNode->mName.data);
+ LoadPiece( model, scene->mRootNode, metaTable );
+
+ // Update piece hierarchy based on metadata
+ BuildPieceHierarchy( model );
+
+ // Simplified dimensions used for rough calculations
+ model->radius = metaTable.GetFloat("radius", model->radius);
+ model->height = metaTable.GetFloat("height", model->height);
+ model->relMidPos = metaTable.GetFloat3("midpos", model->relMidPos);
+ model->mins = metaTable.GetFloat3("mins", model->mins);
+ model->maxs = metaTable.GetFloat3("maxs", model->maxs);
+
+ // Calculate model dimensions if not set
+ if (!metaTable.KeyExists("mins") || !metaTable.KeyExists("maxs")) CalculateMinMax( model->rootPiece );
+ if (model->radius < 0.0001f) CalculateRadius( model );
+ if (model->height < 0.0001f) CalculateHeight( model );
+
+ // Verbose logging of model properties
+ logOutput.Print(LOG_MODEL_DETAIL, "model->name: %s", model->name.c_str());
+ logOutput.Print(LOG_MODEL_DETAIL, "model->numobjects: %d", model->numPieces);
+ logOutput.Print(LOG_MODEL_DETAIL, "model->radius: %f", model->radius);
+ logOutput.Print(LOG_MODEL_DETAIL, "model->height: %f", model->height);
+ logOutput.Print(LOG_MODEL_DETAIL, "model->mins: (%f,%f,%f)", model->mins[0], model->mins[1], model->mins[2]);
+ logOutput.Print(LOG_MODEL_DETAIL, "model->maxs: (%f,%f,%f)", model->maxs[0], model->maxs[1], model->maxs[2]);
+
+ logOutput.Print (LOG_MODEL, "Model %s Imported.", model->name.c_str());
+ return model;
+}
+
+SAssPiece* CAssParser::LoadPiece(S3DModel* model, aiNode* node, const LuaTable& metaTable)
+{
+ // Create new piece
+ model->numPieces++;
+ SAssPiece* piece = new SAssPiece;
+ piece->type = MODELTYPE_OTHER;
+ piece->node = node;
+ piece->model = model;
+ piece->isEmpty = node->mNumMeshes == 0;
+
+ if (node->mParent) {
+ piece->name = std::string(node->mName.data);
+ } else {
+ piece->name = "root"; // The real model root
+ }
+ logOutput.Print(LOG_PIECE, "Converting node '%s' to piece '%s' (%d meshes).", node->mName.data, piece->name.c_str(), node->mNumMeshes);
+
+ // Load additional piece properties from metadata
+ const LuaTable& pieceTable = metaTable.SubTable("pieces").SubTable(piece->name);
+ if (pieceTable.IsValid()) logOutput.Print(LOG_PIECE, "Found metadata for piece '%s'", piece->name.c_str());
+
+ // Process transforms
+ float3 rotate, scale, offset;
+ aiVector3D _scale, _offset;
+ aiQuaternion _rotate;
+ node->mTransformation.Decompose(_scale,_rotate,_offset);
+
+ logOutput.Print(LOG_PIECE, "(%d:%s) Assimp offset (%f,%f,%f), rotate (%f,%f,%f), scale (%f,%f,%f)", model->numPieces, piece->name.c_str(),
+ _offset.x, _offset.y, _offset.z,
+ _rotate.x, _rotate.y, _rotate.z,
+ _scale.x, _scale.y, _scale.z
+ );
+
+ offset = pieceTable.GetFloat3("offset", float3(_offset.x, _offset.y, _offset.z));
+ offset.x = pieceTable.GetFloat("offsetx", offset.x);
+ offset.y = pieceTable.GetFloat("offsety", offset.y);
+ offset.z = pieceTable.GetFloat("offsetz", offset.z);
+
+ if (pieceTable.KeyExists("rotate")) {
+ rotate = pieceTable.GetFloat3("rotate", float3(0.0f, 0.0f, 0.0f));
+ DegreesToRadianAngles(rotate);
+ } else {
+ rotate = QuaternionToRadianAngles(_rotate);
+ rotate = float3(rotate.z, rotate.x, rotate.y);
+ }
+ if (pieceTable.KeyExists("rotatex")) rotate.x = pieceTable.GetFloat("rotatex", 0.0f) * DEGTORAD;
+ if (pieceTable.KeyExists("rotatey")) rotate.y = pieceTable.GetFloat("rotatey", 0.0f) * DEGTORAD;
+ if (pieceTable.KeyExists("rotatez")) rotate.z = pieceTable.GetFloat("rotatez", 0.0f) * DEGTORAD;
+
+ scale = pieceTable.GetFloat3("scale", float3(_scale.x, _scale.z, _scale.y));
+ scale.x = pieceTable.GetFloat("scalex", scale.x);
+ scale.y = pieceTable.GetFloat("scaley", scale.y);
+ scale.z = pieceTable.GetFloat("scalez", scale.z);
+
+ logOutput.Print(LOG_PIECE, "(%d:%s) Relative offset (%f,%f,%f), rotate (%f,%f,%f), scale (%f,%f,%f)", model->numPieces, piece->name.c_str(),
+ offset.x, offset.y, offset.z,
+ rotate.x, rotate.y, rotate.z,
+ scale.x, scale.y, scale.z
+ );
+ piece->offset = offset;
+ piece->rot = rotate;
+ piece->scale = scale;
+
+ // Get vertex data from node meshes
+ for ( unsigned meshListIndex = 0; meshListIndex < node->mNumMeshes; meshListIndex++ ) {
+ unsigned int meshIndex = node->mMeshes[meshListIndex];
+ logOutput.Print(LOG_PIECE_DETAIL, "Fetching mesh %d from scene", meshIndex );
+ aiMesh* mesh = model->scene->mMeshes[meshIndex];
+ std::vector<unsigned> mesh_vertex_mapping;
+ // extract vertex data
+ logOutput.Print(LOG_PIECE_DETAIL, "Processing vertices for mesh %d (%d vertices)", meshIndex, mesh->mNumVertices );
+ logOutput.Print(LOG_PIECE_DETAIL, "Normals: %s Tangents/Bitangents: %s TexCoords: %s",
+ (mesh->HasNormals())?"Y":"N",
+ (mesh->HasTangentsAndBitangents())?"Y":"N",
+ (mesh->HasTextureCoords(0)?"Y":"N")
+ );
+ for ( unsigned vertexIndex= 0; vertexIndex < mesh->mNumVertices; vertexIndex++) {
+ SAssVertex vertex;
+
+ // vertex coordinates
+ logOutput.Print(LOG_PIECE_DETAIL, "Fetching vertex %d from mesh", vertexIndex );
+ aiVector3D& aiVertex = mesh->mVertices[vertexIndex];
+ vertex.pos.x = aiVertex.x;
+ vertex.pos.y = aiVertex.y;
+ vertex.pos.z = aiVertex.z;
+
+ // update piece min/max extents
+ piece->mins.x = std::min(piece->mins.x, aiVertex.x);
+ piece->mins.y = std::min(piece->mins.y, aiVertex.y);
+ piece->mins.z = std::min(piece->mins.z, aiVertex.z);
+ piece->maxs.x = std::max(piece->maxs.x, aiVertex.x);
+ piece->maxs.y = std::max(piece->maxs.y, aiVertex.y);
+ piece->maxs.z = std::max(piece->maxs.z, aiVertex.z);
+
+ logOutput.Print(LOG_PIECE_DETAIL, "vertex position %d: %f %f %f", vertexIndex, vertex.pos.x, vertex.pos.y, vertex.pos.z );
+
+ // vertex normal
+ logOutput.Print(LOG_PIECE_DETAIL, "Fetching normal for vertex %d", vertexIndex );
+ aiVector3D& aiNormal = mesh->mNormals[vertexIndex];
+ vertex.hasNormal = !IS_QNAN(aiNormal);
+ if ( vertex.hasNormal ) {
+ vertex.normal.x = aiNormal.x;
+ vertex.normal.y = aiNormal.y;
+ vertex.normal.z = aiNormal.z;
+ logOutput.Print(LOG_PIECE_DETAIL, "vertex normal %d: %f %f %f",vertexIndex, vertex.normal.x, vertex.normal.y,vertex.normal.z );
+ }
+
+ // vertex tangent, x is positive in texture axis
+ if (mesh->HasTangentsAndBitangents()) {
+ logOutput.Print(LOG_PIECE_DETAIL, "Fetching tangent for vertex %d", vertexIndex );
+ aiVector3D& aiTangent = mesh->mTangents[vertexIndex];
+ vertex.hasTangent = !IS_QNAN(aiTangent);
+ if ( vertex.hasTangent ) {
+ float3 tangent;
+ tangent.x = aiTangent.x;
+ tangent.y = aiTangent.y;
+ tangent.z = aiTangent.z;
+ logOutput.Print(LOG_PIECE_DETAIL, "vertex tangent %d: %f %f %f",vertexIndex, tangent.x, tangent.y,tangent.z );
+ piece->sTangents.push_back(tangent);
+ // bitangent is cross product of tangent and normal
+ float3 bitangent;
+ if ( vertex.hasNormal ) {
+ bitangent = tangent.cross(vertex.normal);
+ logOutput.Print(LOG_PIECE_DETAIL, "vertex bitangent %d: %f %f %f",vertexIndex, bitangent.x, bitangent.y,bitangent.z );
+ piece->tTangents.push_back(bitangent);
+ }
+ }
+ } else {
+ vertex.hasTangent = false;
+ }
+
+ // vertex texcoords
+ if (mesh->HasTextureCoords(0)) {
+ vertex.textureX = mesh->mTextureCoords[0][vertexIndex].x;
+ vertex.textureY = mesh->mTextureCoords[0][vertexIndex].y;
+ logOutput.Print(LOG_PIECE_DETAIL, "vertex texcoords %d: %f %f", vertexIndex, vertex.textureX, vertex.textureY );
+ }
+
+ mesh_vertex_mapping.push_back(piece->vertices.size());
+ piece->vertices.push_back(vertex);
+ }
+
+ // extract face data
+ if ( mesh->HasFaces() ) {
+ logOutput.Print(LOG_PIECE_DETAIL, "Processing faces for mesh %d (%d faces)", meshIndex, mesh->mNumFaces);
+ for ( unsigned faceIndex = 0; faceIndex < mesh->mNumFaces; faceIndex++ ) {
+ aiFace& face = mesh->mFaces[faceIndex];
+ // get the vertex belonging to the mesh
+ for ( unsigned vertexListID = 0; vertexListID < face.mNumIndices; vertexListID++ ) {
+ unsigned int vertexID = mesh_vertex_mapping[face.mIndices[vertexListID]];
+ logOutput.Print(LOG_PIECE_DETAIL, "face %d vertex %d", faceIndex, vertexID );
+ piece->vertexDrawOrder.push_back(vertexID);
+ }
+ }
+ }
+ }
+
+ // Check if piece is special (ie, used to set Spring model properties)
+ if (strcmp(node->mName.data, "SpringHeight") == 0) {
+ // Set the model height to this nodes Z value
+ if (!metaTable.KeyExists("height")) {
+ model->height = piece->offset.z;
+ logOutput.Print (LOG_MODEL, "Model height of %f set by special node 'SpringHeight'", model->height);
+ }
+ return NULL;
+ }
+ if (strcmp(node->mName.data, "SpringRadius") == 0) {
+ if (!metaTable.KeyExists("midpos")) {
+ model->relMidPos = float3(piece->offset.x, piece->offset.z, piece->offset.y); // Y and Z are swapped because this piece isn't rotated
+ logOutput.Print (LOG_MODEL, "Model midpos of (%f,%f,%f) set by special node 'SpringRadius'", model->relMidPos.x, model->relMidPos.y, model->relMidPos.z);
+ }
+ if (!metaTable.KeyExists("radius")) {
+ if (piece->maxs.x <= 0.00001f) {
+ model->radius = piece->scale.x; // the blender import script only sets the scale property
+ } else {
+ model->radius = piece->maxs.x; // use the transformed mesh extents
+ }
+ logOutput.Print (LOG_MODEL, "Model radius of %f set by special node 'SpringRadius'", model->radius);
+ }
+ return NULL;
+ }
+
+ // collision volume for piece (not sure about these coords)
+ const float3 cvScales = (piece->maxs) - (piece->mins);
+ const float3 cvOffset = (piece->maxs - piece->offset) + (piece->mins - piece->offset);
+ //const float3 cvOffset(piece->offset.x, piece->offset.y, piece->offset.z);
+ piece->colvol = new CollisionVolume("box", cvScales, cvOffset, CollisionVolume::COLVOL_HITTEST_CONT);
+
+ // Get parent name from metadata or model
+ if (pieceTable.KeyExists("parent")) {
+ piece->parentName = pieceTable.GetString("parent", "");
+ } else if (node->mParent) {
+ if (node->mParent->mParent) {
+ piece->parentName = std::string(node->mParent->mName.data);
+ } else { // my parent is the root, which gets renamed
+ piece->parentName = "root";
+ }
+ } else {
+ piece->parentName = "";
+ }
+
+ logOutput.Print(LOG_PIECE, "Loaded model piece: %s with %d meshes\n", piece->name.c_str(), node->mNumMeshes );
+
+ // Verbose logging of piece properties
+ logOutput.Print(LOG_PIECE, "piece->name: %s", piece->name.c_str());
+ logOutput.Print(LOG_PIECE, "piece->parent: %s", piece->parentName.c_str());
+
+ // Recursively process all child pieces
+ for (unsigned int i = 0; i < node->mNumChildren; ++i) {
+ LoadPiece(model, node->mChildren[i], metaTable);
+ }
+
+ model->pieces[piece->name] = piece;
+ return piece;
+}
+
+// Because of metadata overrides we don't know the true hierarchy until all pieces have been loaded
+void CAssParser::BuildPieceHierarchy( S3DModel* model )
+{
+ // Loop through all pieces and create missing hierarchy info
+ ModelPieceMap::const_iterator end = model->pieces.end();
+ for (ModelPieceMap::const_iterator it = model->pieces.begin(); it != end; ++it)
+ {
+ S3DModelPiece* piece = it->second;
+ if (piece->name == "root") {
+ piece->parent = NULL;
+ model->SetRootPiece(piece);
+ } else if (piece->parentName != "") {
+ piece->parent = model->FindPiece(piece->parentName);
+ if (piece->parent == NULL) {
+ logOutput.Print( LOG_PIECE, "Error: Missing piece '%s' declared as parent of '%s'.\n", piece->parentName.c_str(), piece->name.c_str() );
+ } else {
+ piece->parent->childs.push_back(piece);
+ }
+ } else {
+ // A piece with no parent that isn't the root (orphan)
+ piece->parent = model->FindPiece("root");
+ if (piece->parent == NULL) {
+ logOutput.Print( LOG_PIECE, "Error: Missing root piece.\n" );
+ } else {
+ piece->parent->childs.push_back(piece);
+ }
+ }
+ }
+}
+
+// Iterate over the model and calculate its overall dimensions
+void CAssParser::CalculateMinMax( S3DModelPiece* piece )
+{
+ piece->goffset = piece->parent ? piece->parent->goffset + piece->offset : piece->offset;
+
+ // update model min/max extents
+ piece->model->mins.x = std::min(piece->goffset.x + piece->mins.x, piece->model->mins.x);
+ piece->model->mins.y = std::min(piece->goffset.y + piece->mins.y, piece->model->mins.y);
+ piece->model->mins.z = std::min(piece->goffset.z + piece->mins.z, piece->model->mins.z);
+ piece->model->maxs.x = std::max(piece->goffset.x + piece->maxs.x, piece->model->maxs.x);
+ piece->model->maxs.y = std::max(piece->goffset.y + piece->maxs.y, piece->model->maxs.y);
+ piece->model->maxs.z = std::max(piece->goffset.z + piece->maxs.z, piece->model->maxs.z);
+
+ // Repeat with childs
+ for (unsigned int i = 0; i < piece->childs.size(); i++) {
+ CalculateMinMax(piece->childs[i]);
+ }
+}
+
+// Calculate model radius from the min/max extents
+void CAssParser::CalculateRadius( S3DModel* model )
+{
+ model->radius = std::max(model->radius, model->maxs.x);
+ model->radius = std::max(model->radius, model->maxs.y);
+ model->radius = std::max(model->radius, model->maxs.z);
+}
+
+// Calculate model height from the min/max extents
+void CAssParser::CalculateHeight( S3DModel* model )
+{
+ model->height = model->maxs.z;
+}
+
+void DrawPiecePrimitive( const S3DModelPiece* o)
+{
+ if (o->isEmpty) {
+ return;
+ }
+ logOutput.Print(LOG_PIECE_DETAIL, "Compiling piece %s", o->name.c_str());
+ // Add GL commands to the pieces displaylist
+
+ const SAssPiece* so = static_cast<const SAssPiece*>(o);
+ const SAssVertex* sAssV = static_cast<const SAssVertex*>(&so->vertices[0]);
+
+
+ // pass the tangents as 3D texture coordinates
+ // (array elements are float3's, which are 12
+ // bytes in size and each represent a single
+ // xyz triple)
+ // TODO: test if we have this many texunits
+ // (if not, could only send the s-tangents)?
+
+ if (!so->sTangents.empty()) {
+ glClientActiveTexture(GL_TEXTURE5);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(3, GL_FLOAT, sizeof(float3), &so->sTangents[0].x);
+ }
+ if (!so->tTangents.empty()) {
+ glClientActiveTexture(GL_TEXTURE6);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(3, GL_FLOAT, sizeof(float3), &so->tTangents[0].x);
+ }
+
+ glClientActiveTexture(GL_TEXTURE0);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(2, GL_FLOAT, sizeof(SAssVertex), &sAssV->textureX);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(3, GL_FLOAT, sizeof(SAssVertex), &sAssV->pos.x);
+
+ glEnableClientState(GL_NORMAL_ARRAY);
+ glNormalPointer(GL_FLOAT, sizeof(SAssVertex), &sAssV->normal.x);
+
+ // since aiProcess_SortByPType is being used, we're sure we'll get only 1 type here, so combination check isn't needed, also anything more complex than triangles is being split thanks to aiProcess_Triangulate
+ glDrawElements(GL_TRIANGLES, so->vertexDrawOrder.size(), GL_UNSIGNED_INT, &so->vertexDrawOrder[0]);
+
+ if (!so->sTangents.empty()) {
+ glClientActiveTexture(GL_TEXTURE6);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ }
+ if (!so->tTangents.empty()) {
+ glClientActiveTexture(GL_TEXTURE5);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ }
+
+ glClientActiveTexture(GL_TEXTURE0);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_NORMAL_ARRAY);
+
+ logOutput.Print(LOG_PIECE_DETAIL, "Completed compiling piece %s", o->name.c_str());
+}
+
+void CAssParser::Draw( const S3DModelPiece* o) const
+{
+ DrawPiecePrimitive( o );
+}
+
+void SAssPiece::DrawList() const
+{
+ DrawPiecePrimitive(this);
+}
diff --git a/rts/Rendering/Models/AssParser.h b/rts/Rendering/Models/AssParser.h
new file mode 100755
index 0000000..e7a5b70
--- /dev/null
+++ b/rts/Rendering/Models/AssParser.h
@@ -0,0 +1,51 @@
+#ifndef ASSPARSER_H
+#define ASSPARSER_H
+
+#include <map>
+#include "IModelParser.h"
+#include "float3.h"
+
+struct aiNode;
+struct aiScene;
+class LuaTable;
+
+struct SAssVertex {
+ float3 pos;
+ float3 normal;
+ float textureX;
+ float textureY;
+ bool hasNormal;
+ bool hasTangent;
+};
+
+struct SAssPiece: public S3DModelPiece
+{
+public:
+ aiNode* node;
+
+ const float3& GetVertexPos(int idx) const { return vertices[idx].pos; }
+ void DrawList() const;
+ std::vector<SAssVertex> vertices;
+
+ std::vector<unsigned int> vertexDrawOrder;
+ // cannot store these in SAssVertex
+ std::vector<float3> sTangents; // == T(angent) dirs
+ std::vector<float3> tTangents; // == B(itangent) dirs
+};
+
+
+class CAssParser: public IModelParser
+{
+public:
+ S3DModel* Load(const std::string& modelFileName);
+ void Draw(const S3DModelPiece* o) const;
+
+private:
+ SAssPiece* LoadPiece(S3DModel* model, aiNode* node, const LuaTable& metaTable);
+ void BuildPieceHierarchy(S3DModel* model);
+ void CalculateRadius( S3DModel* model );
+ void CalculateHeight( S3DModel* model );
+ void CalculateMinMax( S3DModelPiece* piece );
+};
+
+#endif /* ASSPARSER_H */
diff --git a/rts/Rendering/Models/IModelParser.cpp b/rts/Rendering/Models/IModelParser.cpp
old mode 100644
new mode 100755
index aff59ad..e9513ee
--- a/rts/Rendering/Models/IModelParser.cpp
+++ b/rts/Rendering/Models/IModelParser.cpp
@@ -8,9 +8,12 @@
#include "IModelParser.h"
#include "3DModel.h"
+#include "3DModelLog.h"
#include "3DOParser.h"
#include "S3OParser.h"
#include "OBJParser.h"
+#include "AssParser.h"
+#include "assimp.hpp"
#include "Sim/Misc/CollisionVolume.h"
#include "Sim/Units/Unit.h"
#include "System/FileSystem/FileSystem.h"
@@ -18,10 +21,8 @@
#include "System/LogOutput.h"
#include "System/Exceptions.h"
-
C3DModelLoader* modelParser = NULL;
-
//////////////////////////////////////////////////////////////////////
// C3DModelLoader
//
@@ -31,7 +32,26 @@ C3DModelLoader::C3DModelLoader()
// file-extension should be lowercase
parsers["3do"] = new C3DOParser();
parsers["s3o"] = new CS3OParser();
- parsers["obj"] = new COBJParser();
+ //parsers["obj"] = new COBJParser(); // replaced by Assimp
+
+ // assimp library
+ CAssParser* unitassparser = new CAssParser();
+ std::string extensionlist;
+
+ Assimp::Importer importer;
+ importer.GetExtensionList(extensionlist); // get a ";" separated list of wildcards
+ char* charextensionlist = new char[extensionlist.size() +1];
+ strcpy (charextensionlist, extensionlist.c_str());
+ logOutput.Print("Assimp: Supported model formats: %s", extensionlist.c_str());
+ char* extensionchar = strtok( charextensionlist, ";" );
+ while( extensionchar )
+ {
+ std::string extension = extensionchar;
+ extension = extension.substr( 2 ); // strip wildcard and dot
+ parsers[extension] = unitassparser; // register extension
+ extensionchar = strtok( NULL, ";" );
+ }
+ delete charextensionlist;
}
@@ -48,11 +68,15 @@ C3DModelLoader::~C3DModelLoader()
cache.clear();
// delete parsers
+ std::set<IModelParser*> dedupe_parsers; // this is to avoid deleting the same parser twice, if it's assigned to multiple model formats
std::map<std::string, IModelParser*>::iterator pi;
for (pi = parsers.begin(); pi != parsers.end(); ++pi) {
+ if ( dedupe_parsers.count( pi->second ) != 0 ) continue;
+ dedupe_parsers.insert( pi->second );
delete pi->second;
}
parsers.clear();
+ dedupe_parsers.clear();
#if defined(USE_GML) && GML_ENABLE_SIM
createLists.clear();
@@ -67,7 +91,7 @@ inline int ModelExtToModelType(const std::string& ext) {
if (ext == "3do") { return MODELTYPE_3DO; }
if (ext == "s3o") { return MODELTYPE_S3O; }
if (ext == "obj") { return MODELTYPE_OBJ; }
- return -1;
+ return MODELTYPE_ASS; // FIXME: Return -1 if Assimp cant handle extension
}
inline S3DModelPiece* ModelTypeToModelPiece(int type) {
if (type == MODELTYPE_3DO) { return (new S3DOPiece()); }
diff --git a/rts/Rendering/Models/WorldObjectModelRenderer.cpp b/rts/Rendering/Models/WorldObjectModelRenderer.cpp
old mode 100644
new mode 100755
index 778f11b..bd8237b
--- a/rts/Rendering/Models/WorldObjectModelRenderer.cpp
+++ b/rts/Rendering/Models/WorldObjectModelRenderer.cpp
@@ -14,6 +14,7 @@ IWorldObjectModelRenderer* IWorldObjectModelRenderer::GetInstance(int modelType)
case MODELTYPE_3DO: { return (new WorldObjectModelRenderer3DO()); } break;
case MODELTYPE_S3O: { return (new WorldObjectModelRendererS3O()); } break;
case MODELTYPE_OBJ: { return (new WorldObjectModelRendererOBJ()); } break;
+ case MODELTYPE_ASS: { return (new WorldObjectModelRendererASS()); } break;
default: { return (new IWorldObjectModelRenderer(MODELTYPE_OTHER)); } break;
}
}
@@ -226,7 +227,18 @@ void WorldObjectModelRendererOBJ::PopRenderState()
// WRITEME
}
-
+void WorldObjectModelRendererASS::PushRenderState()
+{
+ #if (WORLDOBJECT_MODEL_RENDERER_DEBUG == 1)
+ #endif
+ // WRITEME
+}
+void WorldObjectModelRendererASS::PopRenderState()
+{
+ #if (WORLDOBJECT_MODEL_RENDERER_DEBUG == 1)
+ #endif
+ // WRITEME
+}
void WorldObjectModelRendererS3O::DrawModel(const CUnit* u)
{
diff --git a/rts/Rendering/Models/WorldObjectModelRenderer.h b/rts/Rendering/Models/WorldObjectModelRenderer.h
old mode 100644
new mode 100755
index 386da99..11a7644
--- a/rts/Rendering/Models/WorldObjectModelRenderer.h
+++ b/rts/Rendering/Models/WorldObjectModelRenderer.h
@@ -117,4 +117,11 @@ public:
void PopRenderState();
};
+class WorldObjectModelRendererASS: public IWorldObjectModelRenderer {
+public:
+ WorldObjectModelRendererASS(): IWorldObjectModelRenderer(MODELTYPE_ASS) {}
+ void PushRenderState();
+ void PopRenderState();
+};
+
#endif
diff --git a/rts/Rendering/ProjectileDrawer.cpp b/rts/Rendering/ProjectileDrawer.cpp
old mode 100644
new mode 100755
diff --git a/rts/Rendering/Textures/Bitmap.cpp b/rts/Rendering/Textures/Bitmap.cpp
old mode 100644
new mode 100755
index 2445c31..0e31ad6
--- a/rts/Rendering/Textures/Bitmap.cpp
+++ b/rts/Rendering/Textures/Bitmap.cpp
@@ -282,9 +282,9 @@ bool CBitmap::LoadGrayscale(const std::string& filename)
delete[] mem;
mem = new unsigned char[xsize * ysize];
memcpy(mem, ilGetData(), xsize * ysize);
-
+
ilDeleteImages(1, &ImageName);
-
+
return true;
}
@@ -738,6 +738,18 @@ void CBitmap::InvertColors()
}
+void CBitmap::InvertAlpha()
+{
+ if (type != BitmapTypeStandardRGBA) return; // Don't try to invert DDS
+ for (int y = 0; y < ysize; ++y) {
+ for (int x = 0; x < xsize; ++x) {
+ const int base = ((y * xsize) + x) * 4;
+ mem[base + 3] = 0xFF - mem[base + 3];
+ }
+ }
+}
+
+
void CBitmap::GrayScale()
{
if (type != BitmapTypeStandardRGBA) {
@@ -786,6 +798,7 @@ void CBitmap::Tint(const float tint[3])
void CBitmap::ReverseYAxis()
{
+ if (type != BitmapTypeStandardRGBA) return; // don't try to flip DDS
unsigned char* tmpLine = new unsigned char[channels * xsize];
for (int y=0; y < (ysize / 2); ++y) {
const int pixelLow = (((y ) * xsize) + 0) * channels;
diff --git a/rts/Rendering/Textures/Bitmap.h b/rts/Rendering/Textures/Bitmap.h
old mode 100644
new mode 100755
index 9b1577b..9d984f9
--- a/rts/Rendering/Textures/Bitmap.h
+++ b/rts/Rendering/Textures/Bitmap.h
@@ -83,6 +83,7 @@ public:
CBitmap CreateRescaled(int newx, int newy) const;
void ReverseYAxis();
void InvertColors();
+ void InvertAlpha();
void GrayScale();
void Tint(const float tint[3]);
};
diff --git a/rts/Rendering/Textures/S3OTextureHandler.cpp b/rts/Rendering/Textures/S3OTextureHandler.cpp
old mode 100644
new mode 100755
index 857406b..abb6a02
--- a/rts/Rendering/Textures/S3OTextureHandler.cpp
+++ b/rts/Rendering/Textures/S3OTextureHandler.cpp
@@ -20,6 +20,15 @@
#include "System/Exceptions.h"
#include "System/LogOutput.h"
+static CLogSubsystem LOG_TEXTURE("Texture");
+
+// The S3O texture handler uses two textures.
+// The first contains diffuse color (RGB) and teamcolor (A)
+// The second contains glow (R), reflectivity (G) and 1-bit Alpha (A).
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
CS3OTextureHandler* texturehandlerS3O = NULL;
@@ -52,6 +61,10 @@ void CS3OTextureHandler::Update() {
int CS3OTextureHandler::LoadS3OTextureNow(const S3DModel* model)
{
GML_STDMUTEX_LOCK(model); // LoadS3OTextureNow
+ logOutput.Print(LOG_TEXTURE, "Load S3O texture now (Flip Y Axis: %s, Invert Team Alpha: %s)",
+ model->flipTexY ? "yes" : "no",
+ model->invertTexAlpha ? "yes" : "no"
+ );
const string totalName = model->tex1 + model->tex2;
@@ -74,6 +87,8 @@ int CS3OTextureHandler::LoadS3OTextureNow(const S3DModel* model)
tex1bm.mem[2] = 0;
tex1bm.mem[3] = 255;
}
+ if (model->flipTexY) tex1bm.ReverseYAxis();
+ if (model->invertTexAlpha) tex1bm.InvertAlpha();
tex.num = s3oTextures.size();
tex.tex1 = tex1bm.CreateTexture(true);
@@ -92,6 +107,7 @@ int CS3OTextureHandler::LoadS3OTextureNow(const S3DModel* model)
tex2bm.mem[2] = 0; // unused
tex2bm.mem[3] = 255; // team-color
}
+ if (model->flipTexY) tex2bm.ReverseYAxis();
tex.tex2 = tex2bm.CreateTexture(true);
tex.tex2SizeX = tex2bm.xsize;
diff --git a/rts/Rendering/Textures/S3OTextureHandler.h b/rts/Rendering/Textures/S3OTextureHandler.h
old mode 100644
new mode 100755
diff --git a/rts/Rendering/UnitDrawer.cpp b/rts/Rendering/UnitDrawer.cpp
old mode 100644
new mode 100755
index 9dc973b..f6ca177
--- a/rts/Rendering/UnitDrawer.cpp
+++ b/rts/Rendering/UnitDrawer.cpp
@@ -519,7 +519,7 @@ void CUnitDrawer::DrawOpaqueUnits(int modelType, const CUnit* excludeUnit, bool
UnitSet::const_iterator unitSetIt;
for (unitBinIt = unitBin.begin(); unitBinIt != unitBin.end(); ++unitBinIt) {
- if (modelType == MODELTYPE_S3O || modelType == MODELTYPE_OBJ) {
+ if (modelType == MODELTYPE_S3O || modelType == MODELTYPE_OBJ || modelType == MODELTYPE_ASS) {
texturehandlerS3O->SetS3oTexture(unitBinIt->first);
}
@@ -779,13 +779,13 @@ inline void CUnitDrawer::DrawOpaqueUnitShadow(CUnit* unit) {
#define S3O_TEX(model) \
texturehandlerS3O->GetS3oTex(model->textureType)
#define PUSH_SHADOW_TEXTURE_STATE(model) \
- if (model->type == MODELTYPE_S3O || model->type == MODELTYPE_OBJ) { \
+ if (model->type == MODELTYPE_S3O || model->type == MODELTYPE_OBJ || model->type == MODELTYPE_ASS) { \
glActiveTexture(GL_TEXTURE0); \
glEnable(GL_TEXTURE_2D); \
glBindTexture(GL_TEXTURE_2D, S3O_TEX(model)->tex2); \
}
#define POP_SHADOW_TEXTURE_STATE(model) \
- if (model->type == MODELTYPE_S3O || model->type == MODELTYPE_OBJ) { \
+ if (model->type == MODELTYPE_S3O || model->type == MODELTYPE_OBJ || model->type == MODELTYPE_ASS) { \
glBindTexture(GL_TEXTURE_2D, 0); \
glDisable(GL_TEXTURE_2D); \
glActiveTexture(GL_TEXTURE0); \
@@ -1042,7 +1042,7 @@ void CUnitDrawer::DrawCloakedUnitsHelper(int modelType)
// cloaked units
for (UnitRenderBinIt it = unitBin.begin(); it != unitBin.end(); ++it) {
- if (modelType == MODELTYPE_S3O || modelType == MODELTYPE_OBJ) {
+ if (modelType == MODELTYPE_S3O || modelType == MODELTYPE_OBJ || modelType == MODELTYPE_ASS) {
texturehandlerS3O->SetS3oTexture(it->first);
}
@@ -1099,7 +1099,7 @@ inline void CUnitDrawer::DrawCloakedUnit(CUnit* unit, int modelType, bool drawGh
glTranslatef3(unit->pos);
glRotatef(unit->buildFacing * 90.0f, 0, 1, 0);
- if (modelType == MODELTYPE_S3O || modelType == MODELTYPE_OBJ) {
+ if (modelType == MODELTYPE_S3O || modelType == MODELTYPE_OBJ || modelType == MODELTYPE_ASS) {
// the units in liveGhostedBuildings[modelType] are not
// sorted by textureType, but we cannot merge them with
// cloakedModelRenderers[modelType] since they are not
@@ -1183,7 +1183,7 @@ void CUnitDrawer::DrawGhostedBuildings(int modelType)
glTranslatef3((*it)->pos);
glRotatef((*it)->facing * 90.0f, 0, 1, 0);
- if (modelType == MODELTYPE_S3O || modelType == MODELTYPE_OBJ)
+ if (modelType == MODELTYPE_S3O || modelType == MODELTYPE_OBJ || modelType == MODELTYPE_ASS)
texturehandlerS3O->SetS3oTexture((*it)->model->textureType);
SetTeamColour((*it)->team, cloakAlpha1);
@@ -1559,7 +1559,7 @@ void CUnitDrawer::DrawIndividual(CUnit* unit)
SetupForUnitDrawing();
opaqueModelRenderers[MDL_TYPE(unit)]->PushRenderState();
- if (MDL_TYPE(unit) == MODELTYPE_S3O || MDL_TYPE(unit) == MODELTYPE_OBJ) {
+ if (MDL_TYPE(unit) == MODELTYPE_S3O || MDL_TYPE(unit) == MODELTYPE_OBJ || MDL_TYPE(unit) == MODELTYPE_ASS) {
texturehandlerS3O->SetS3oTexture(TEX_TYPE(unit));
}
@@ -1599,7 +1599,8 @@ void CUnitDrawer::DrawBuildingSample(const UnitDef* unitdef, int side, float3 po
texturehandler3DO->Set3doAtlases();
} break;
case MODELTYPE_S3O:
- case MODELTYPE_OBJ: {
+ case MODELTYPE_OBJ:
+ case MODELTYPE_ASS: {
texturehandlerS3O->SetS3oTexture(model->textureType);
} break;
default: {
@@ -1987,7 +1988,7 @@ inline void CUnitDrawer::UpdateUnitIconState(CUnit* unit) {
#ifdef USE_GML
if (showHealthBars && !unit->noDraw &&
(unit->health < unit->maxHealth || unit->paralyzeDamage > 0.0f || unit->limExperience > 0.0f ||
- unit->beingBuilt || unit->stockpileWeapon || unit->group) &&
+ unit->beingBuilt || unit->stockpileWeapon || unit->group) &&
((unit->pos - camera->pos).SqLength() < (unitDrawDistSqr * 500.0f)))
drawStat.insert(unit);
#endif
diff --git a/rts/Sim/Misc/GlobalConstants.h b/rts/Sim/Misc/GlobalConstants.h
index 78c5305..6006a4e 100644
--- a/rts/Sim/Misc/GlobalConstants.h
+++ b/rts/Sim/Misc/GlobalConstants.h
@@ -39,6 +39,13 @@ const int UNIT_SLOWUPDATE_RATE = 16;
const int TEAM_SLOWUPDATE_RATE = 32;
/**
+ * @brief max view range
+ *
+ * Defines the maximum view range as 8000
+ */
+const int MAX_VIEW_RANGE = 8000;
+
+/**
* @brief max teams
*
* Defines the maximum number of teams
@@ -56,10 +63,9 @@ const int MAX_PLAYERS = 251;
/**
* @brief max units
*
- * Defines the absolute global maximum number of units allowed to exist in a game.
- * MUST be <= SHRT_MAX ((1 << ((sizeof(short) * 8) - 1)) - 1) because current net
- * code transmits unit ID's as signed shorts. The effective global unit limit is
- * stored in UnitHandler::maxUnits and is always clamped to this value.
+ * Defines the maximum number of untis that may be set as maximum for a game.
+ * The real maximum of the game is stored in uh->maxUnits,
+ * and may not be higher then this value.
*/
const int MAX_UNITS = 32000;
@@ -69,6 +75,13 @@ const int MAX_UNITS = 32000;
const int MAX_WEAPONS_PER_UNIT = 32;
/**
+ * @brief near plane
+ *
+ * Defines the near plane as 2.8f
+ */
+const float NEAR_PLANE = 2.8f;
+
+/**
* @brief randint max
*
* Defines the maximum random integer as 0x7fff
diff --git a/rts/Sim/Misc/Team.cpp b/rts/Sim/Misc/Team.cpp
index 407c17f..3b84cc6 100644
--- a/rts/Sim/Misc/Team.cpp
+++ b/rts/Sim/Misc/Team.cpp
@@ -27,52 +27,56 @@
CR_BIND(CTeam,);
CR_REG_METADATA(CTeam, (
- // from CTeamBase
- CR_MEMBER(leader),
- CR_MEMBER(color),
- CR_MEMBER(incomeMultiplier),
- CR_MEMBER(side),
- CR_MEMBER(startPos),
- CR_MEMBER(teamStartNum),
- CR_MEMBER(teamAllyteam),
- // CR_MEMBER(customValues),
- // from CTeam
- CR_MEMBER(teamNum),
- CR_MEMBER(isDead),
- CR_MEMBER(gaia),
- CR_MEMBER(origColor),
- CR_MEMBER(units),
- CR_MEMBER(metal),
- CR_MEMBER(energy),
- CR_MEMBER(metalPull),
- CR_MEMBER(prevMetalPull),
- CR_MEMBER(metalIncome),
- CR_MEMBER(prevMetalIncome),
- CR_MEMBER(metalExpense),
- CR_MEMBER(prevMetalExpense),
- CR_MEMBER(energyPull),
- CR_MEMBER(prevEnergyPull),
- CR_MEMBER(energyIncome),
- CR_MEMBER(prevEnergyIncome),
- CR_MEMBER(energyExpense),
- CR_MEMBER(prevEnergyExpense),
- CR_MEMBER(metalStorage),
- CR_MEMBER(energyStorage),
- CR_MEMBER(metalShare),
- CR_MEMBER(energyShare),
- CR_MEMBER(delayedMetalShare),
- CR_MEMBER(delayedEnergyShare),
- CR_MEMBER(metalSent),
- CR_MEMBER(metalReceived),
- CR_MEMBER(energySent),
- CR_MEMBER(energyReceived),
- //CR_MEMBER(currentStats),
- CR_MEMBER(nextHistoryEntry),
- //CR_MEMBER(statHistory),
- CR_MEMBER(modParams),
- CR_MEMBER(modParamsMap),
- CR_RESERVED(64)
-));
+// from CTeamBase
+ CR_MEMBER(leader),
+ CR_MEMBER(color),
+ CR_MEMBER(incomeMultiplier),
+ CR_MEMBER(side),
+ CR_MEMBER(startPos),
+ CR_MEMBER(teamStartNum),
+ CR_MEMBER(teamAllyteam),
+// CR_MEMBER(customValues),
+// from CTeam
+ CR_MEMBER(teamNum),
+ CR_MEMBER(isDead),
+ CR_MEMBER(gaia),
+ CR_MEMBER(origColor),
+ CR_MEMBER(units),
+ CR_MEMBER(metal),
+ CR_MEMBER(energy),
+ CR_MEMBER(metalPull),
+ CR_MEMBER(prevMetalPull),
+ CR_MEMBER(metalIncome),
+ CR_MEMBER(prevMetalIncome),
+ CR_MEMBER(metalExpense),
+ CR_MEMBER(prevMetalExpense),
+ CR_MEMBER(metalUpkeep),
+ CR_MEMBER(prevMetalUpkeep),
+ CR_MEMBER(energyPull),
+ CR_MEMBER(prevEnergyPull),
+ CR_MEMBER(energyIncome),
+ CR_MEMBER(prevEnergyIncome),
+ CR_MEMBER(energyExpense),
+ CR_MEMBER(prevEnergyExpense),
+ CR_MEMBER(energyUpkeep),
+ CR_MEMBER(prevEnergyUpkeep),
+ CR_MEMBER(metalStorage),
+ CR_MEMBER(energyStorage),
+ CR_MEMBER(metalShare),
+ CR_MEMBER(energyShare),
+ CR_MEMBER(delayedMetalShare),
+ CR_MEMBER(delayedEnergyShare),
+ CR_MEMBER(metalSent),
+ CR_MEMBER(metalReceived),
+ CR_MEMBER(energySent),
+ CR_MEMBER(energyReceived),
+ //CR_MEMBER(currentStats),
+ CR_MEMBER(nextHistoryEntry),
+ //CR_MEMBER(statHistory),
+ CR_MEMBER(modParams),
+ CR_MEMBER(modParamsMap),
+ CR_RESERVED(64)
+ ));
//////////////////////////////////////////////////////////////////////
@@ -88,9 +92,11 @@ CTeam::CTeam() :
metalPull(0.0f), prevMetalPull(0.0f),
metalIncome(0.0f), prevMetalIncome(0.0f),
metalExpense(0.0f), prevMetalExpense(0.0f),
+ metalUpkeep(0.0f), prevMetalUpkeep(0.0f),
energyPull(0.0f), prevEnergyPull(0.0f),
energyIncome(0.0f), prevEnergyIncome(0.0f),
energyExpense(0.0f), prevEnergyExpense(0.0f),
+ energyUpkeep(0.0f), prevEnergyUpkeep(0.0f),
metalStorage(1000000),
energyStorage(1000000),
metalShare(0.99f),
@@ -114,10 +120,14 @@ CTeam::CTeam() :
}
+CTeam::~CTeam()
+{
+}
+
bool CTeam::UseMetal(float amount)
{
- if (metal >= amount) {
+ if ((metal - (prevMetalUpkeep * 10)) >= amount) {
metal -= amount;
metalExpense += amount;
return true;
@@ -125,9 +135,10 @@ bool CTeam::UseMetal(float amount)
return false;
}
+
bool CTeam::UseEnergy(float amount)
{
- if (energy >= amount) {
+ if ((energy - (prevEnergyUpkeep * 10)) >= amount) {
energy -= amount;
energyExpense += amount;
return true;
@@ -136,6 +147,29 @@ bool CTeam::UseEnergy(float amount)
}
+bool CTeam::UseMetalUpkeep(float amount)
+{
+ if (metal >= amount) {
+ metal -= amount;
+ metalExpense += amount;
+ metalUpkeep += amount;
+ return true;
+ }
+ return false;
+}
+
+
+bool CTeam::UseEnergyUpkeep(float amount)
+{
+ if (energy >= amount) {
+ energy -= amount;
+ energyExpense += amount;
+ energyUpkeep += amount;
+ return true;
+ }
+ return false;
+}
+
void CTeam::AddMetal(float amount, bool useIncomeMultiplier)
{
@@ -143,24 +177,23 @@ void CTeam::AddMetal(float amount, bool useIncomeMultiplier)
metal += amount;
metalIncome += amount;
if (metal > metalStorage) {
- delayedMetalShare += (metal - metalStorage);
+ delayedMetalShare += metal - metalStorage;
metal = metalStorage;
}
}
+
void CTeam::AddEnergy(float amount, bool useIncomeMultiplier)
{
if (useIncomeMultiplier) { amount *= GetIncomeMultiplier(); }
energy += amount;
energyIncome += amount;
if (energy > energyStorage) {
- delayedEnergyShare += (energy - energyStorage);
+ delayedEnergyShare += energy - energyStorage;
energy = energyStorage;
}
}
-
-
void CTeam::GiveEverythingTo(const unsigned toTeam)
{
CTeam* target = teamHandler->Team(toTeam);
@@ -220,6 +253,10 @@ void CTeam::Died()
eventHandler.TeamDied(teamNum);
}
+void CTeam::StartposMessage(const float3& pos)
+{
+ startPos = pos;
+}
CTeam& CTeam::operator=(const TeamBase& base)
{
@@ -227,36 +264,43 @@ CTeam& CTeam::operator=(const TeamBase& base)
return *this;
}
-
-
-void CTeam::ResetResourceState()
+void CTeam::ResetFrameVariables()
{
- // reset all state variables that were
- // potentially modified during the last
- // <TEAM_SLOWUPDATE_RATE> frames
- prevMetalPull = metalPull; metalPull = 0.0f;
- prevMetalIncome = metalIncome; metalIncome = 0.0f;
- prevMetalExpense = metalExpense; metalExpense = 0.0f;
- prevEnergyPull = energyPull; energyPull = 0.0f;
- prevEnergyIncome = energyIncome; energyIncome = 0.0f;
- prevEnergyExpense = energyExpense; energyExpense = 0.0f;
-
- // reset the sharing accumulators
- metalSent = 0.0f; metalReceived = 0.0f;
- energySent = 0.0f; energyReceived = 0.0f;
+ prevMetalPull = metalPull;
+ prevMetalIncome = metalIncome;
+ prevMetalExpense = metalExpense;
+ prevMetalUpkeep = metalUpkeep;
+ prevEnergyPull = energyPull;
+ prevEnergyIncome = energyIncome;
+ prevEnergyExpense = energyExpense;
+ prevEnergyUpkeep = energyUpkeep;
+
+ metalPull = 0;
+ metalIncome = 0;
+ metalExpense = 0;
+ metalUpkeep = 0;
+ energyPull = 0;
+ energyIncome = 0;
+ energyExpense = 0;
+ energyUpkeep = 0;
+
+ metalSent = 0;
+ energySent = 0;
+ metalReceived = 0;
+ energyReceived = 0;
}
void CTeam::SlowUpdate()
{
- float eShare = 0.0f, mShare = 0.0f;
+ currentStats->metalProduced += prevMetalIncome;
+ currentStats->energyProduced += prevEnergyIncome;
+ currentStats->metalUsed += prevMetalUpkeep + prevMetalExpense;
+ currentStats->energyUsed += prevEnergyUpkeep + prevEnergyExpense;
- // calculate the total amount of resources that all
- // (allied) teams can collectively receive through
- // sharing
+ float eShare = 0.0f, mShare = 0.0f;
for (int a = 0; a < teamHandler->ActiveTeams(); ++a) {
- CTeam* team = teamHandler->Team(a);
-
if ((a != teamNum) && (teamHandler->AllyTeam(teamNum) == teamHandler->AllyTeam(a))) {
+ CTeam* team = teamHandler->Team(a);
if (team->isDead)
continue;
@@ -265,25 +309,21 @@ void CTeam::SlowUpdate()
}
}
+ metal += delayedMetalShare;
+ energy += delayedEnergyShare;
+ delayedMetalShare = 0;
+ delayedEnergyShare = 0;
- currentStats->metalProduced += prevMetalIncome;
- currentStats->energyProduced += prevEnergyIncome;
- currentStats->metalUsed += prevMetalExpense;
- currentStats->energyUsed += prevEnergyExpense;
-
- metal += delayedMetalShare; delayedMetalShare = 0.0f;
- energy += delayedEnergyShare; delayedEnergyShare = 0.0f;
-
-
- // calculate how much we can share in total (any and all excess resources)
const float eExcess = std::max(0.0f, energy - (energyStorage * energyShare));
const float mExcess = std::max(0.0f, metal - (metalStorage * metalShare));
float de = 0.0f, dm = 0.0f;
- if (eShare > 0.0f) { de = std::min(1.0f, eExcess / eShare); }
- if (mShare > 0.0f) { dm = std::min(1.0f, mExcess / mShare); }
-
- // now evenly distribute our excess resources among allied teams
+ if (eShare > 0.0f) {
+ de = std::min(1.0f, eExcess/eShare);
+ }
+ if (mShare > 0.0f) {
+ dm = std::min(1.0f, mExcess/mShare);
+ }
for (int a = 0; a < teamHandler->ActiveTeams(); ++a) {
if ((a != teamNum) && (teamHandler->AllyTeam(teamNum) == teamHandler->AllyTeam(a))) {
CTeam* team = teamHandler->Team(a);
@@ -291,19 +331,23 @@ void CTeam::SlowUpdate()
continue;
const float edif = std::max(0.0f, (team->energyStorage * 0.99f) - team->energy) * de;
- const float mdif = std::max(0.0f, (team->metalStorage * 0.99f) - team->metal) * dm;
+ energy -= edif;
+ energySent += edif;
+ currentStats->energySent += edif;
+ team->energy += edif;
+ team->energyReceived += edif;
+ team->currentStats->energyReceived += edif;
- energy -= edif; team->energy += edif;
- energySent += edif; team->energyReceived += edif;
- metal -= mdif; team->metal += mdif;
- metalSent += mdif; team->metalReceived += mdif;
-
- currentStats->energySent += edif; team->currentStats->energyReceived += edif;
- currentStats->metalSent += mdif; team->currentStats->metalReceived += mdif;
+ const float mdif = std::max(0.0f, (team->metalStorage * 0.99f) - team->metal) * dm;
+ metal -= mdif;
+ metalSent += mdif;
+ currentStats->metalSent += mdif;
+ team->metal += mdif;
+ team->metalReceived += mdif;
+ team->currentStats->metalReceived += mdif;
}
}
- // clamp resource levels to storage capacity
if (metal > metalStorage) {
currentStats->metalExcess += (metal - metalStorage);
metal = metalStorage;
@@ -325,10 +369,11 @@ void CTeam::SlowUpdate()
nextHistoryEntry = gs->frameNum + statsFrames;
currentStats->frame = nextHistoryEntry;
}
+
}
-void CTeam::AddUnit(CUnit* unit, AddType type)
+void CTeam::AddUnit(CUnit* unit,AddType type)
{
units.insert(unit);
switch (type) {
@@ -348,7 +393,7 @@ void CTeam::AddUnit(CUnit* unit, AddType type)
}
-void CTeam::RemoveUnit(CUnit* unit, RemoveType type)
+void CTeam::RemoveUnit(CUnit* unit,RemoveType type)
{
units.erase(unit);
switch (type) {
diff --git a/rts/Sim/Misc/Team.h b/rts/Sim/Misc/Team.h
index fdd6bcf..f390cbc 100644
--- a/rts/Sim/Misc/Team.h
+++ b/rts/Sim/Misc/Team.h
@@ -21,20 +21,28 @@ class CTeam : public TeamBase, private boost::noncopyable //! cannot allow shall
CR_DECLARE(CTeam);
public:
CTeam();
+ ~CTeam();
+public:
- void ResetResourceState();
+ /**
+ * This has to be called for every team before SlowUpdates start,
+ * otherwise values get overwritten.
+ */
+ void ResetFrameVariables();
void SlowUpdate();
void AddMetal(float amount, bool useIncomeMultiplier = true);
void AddEnergy(float amount, bool useIncomeMultiplier = true);
bool UseEnergy(float amount);
bool UseMetal(float amount);
+ bool UseEnergyUpkeep(float amount);
+ bool UseMetalUpkeep(float amount);
void GiveEverythingTo(const unsigned toTeam);
void Died();
- void StartposMessage(const float3& pos) { startPos = pos; }
+ void StartposMessage(const float3& pos);
CTeam& operator=(const TeamBase& base);
@@ -71,10 +79,12 @@ public:
float metalPull, prevMetalPull;
float metalIncome, prevMetalIncome;
float metalExpense, prevMetalExpense;
+ float metalUpkeep, prevMetalUpkeep;
float energyPull, prevEnergyPull;
float energyIncome, prevEnergyIncome;
float energyExpense, prevEnergyExpense;
+ float energyUpkeep, prevEnergyUpkeep;
SyncedFloat metalStorage, energyStorage;
diff --git a/rts/Sim/Misc/TeamHandler.cpp b/rts/Sim/Misc/TeamHandler.cpp
index 0bbbf99..04e5bd0 100644
--- a/rts/Sim/Misc/TeamHandler.cpp
+++ b/rts/Sim/Misc/TeamHandler.cpp
@@ -25,7 +25,7 @@ CR_REG_METADATA(CTeamHandler, (
));
-CTeamHandler* teamHandler = NULL;
+CTeamHandler* teamHandler;
CTeamHandler::CTeamHandler():
@@ -88,12 +88,12 @@ void CTeamHandler::LoadFromSetup(const CGameSetup* setup)
void CTeamHandler::GameFrame(int frameNum)
{
- if ((frameNum % TEAM_SLOWUPDATE_RATE) == 0) {
+ if (!(frameNum & (TEAM_SLOWUPDATE_RATE-1))) {
for (int a = 0; a < ActiveTeams(); ++a) {
- teams[a]->ResetResourceState();
+ Team(a)->ResetFrameVariables();
}
for (int a = 0; a < ActiveTeams(); ++a) {
- teams[a]->SlowUpdate();
+ Team(a)->SlowUpdate();
}
}
}
diff --git a/rts/Sim/MoveTypes/AAirMoveType.cpp b/rts/Sim/MoveTypes/AAirMoveType.cpp
index 5cabd4e..67943ce 100644
--- a/rts/Sim/MoveTypes/AAirMoveType.cpp
+++ b/rts/Sim/MoveTypes/AAirMoveType.cpp
@@ -39,9 +39,9 @@ AAirMoveType::AAirMoveType(CUnit* unit) :
wantedHeight(80.0f),
collide(true),
useSmoothMesh(false),
- autoLand(true),
lastColWarning(NULL),
lastColWarningType(0),
+ autoLand(true),
lastFuelUpdateFrame(0)
{
useHeading = false;
diff --git a/rts/Sim/MoveTypes/AirMoveType.cpp b/rts/Sim/MoveTypes/AirMoveType.cpp
index f0aade2..bc09cbf 100644
--- a/rts/Sim/MoveTypes/AirMoveType.cpp
+++ b/rts/Sim/MoveTypes/AirMoveType.cpp
@@ -1088,7 +1088,7 @@ void CAirMoveType::SetState(AAirMoveType::AircraftState state)
-void CAirMoveType::ImpulseAdded(const float3&)
+void CAirMoveType::ImpulseAdded(void)
{
if (aircraftState == AIRCRAFT_FLYING) {
owner->speed += owner->residualImpulse;
diff --git a/rts/Sim/MoveTypes/AirMoveType.h b/rts/Sim/MoveTypes/AirMoveType.h
index 2f70cab..bc3db18 100644
--- a/rts/Sim/MoveTypes/AirMoveType.h
+++ b/rts/Sim/MoveTypes/AirMoveType.h
@@ -32,7 +32,7 @@ public:
float engine, const float3& engineVector);
void SetState(AircraftState state);
void UpdateTakeOff(float wantedHeight);
- void ImpulseAdded(const float3&);
+ void ImpulseAdded();
float3 FindLandingPos() const;
void DependentDied(CObject* o);
diff --git a/rts/Sim/MoveTypes/GroundMoveType.cpp b/rts/Sim/MoveTypes/GroundMoveType.cpp
index 58e8670..984aa85 100644
--- a/rts/Sim/MoveTypes/GroundMoveType.cpp
+++ b/rts/Sim/MoveTypes/GroundMoveType.cpp
@@ -81,11 +81,12 @@ CR_REG_METADATA(CGroundMoveType, (
CR_MEMBER(canReverse),
CR_MEMBER(useMainHeading),
+ CR_MEMBER(skidRotSpeed),
+
CR_MEMBER(waypointDir),
CR_MEMBER(flatFrontDir),
CR_MEMBER(skidRotVector),
- CR_MEMBER(skidRotSpeed),
CR_MEMBER(skidRotSpeed2),
CR_MEMBER(skidRotPos2),
CR_ENUM_MEMBER(oldPhysState),
@@ -110,10 +111,10 @@ CGroundMoveType::CGroundMoveType(CUnit* owner):
maxReverseSpeed(0.0f),
wantedSpeed(0.0f),
currentSpeed(0.0f),
- requestedSpeed(0.0f),
deltaSpeed(0.0f),
deltaHeading(0),
+ flatFrontDir(0.0f, 0.0, 1.0f),
pathId(0),
goalRadius(0),
@@ -121,7 +122,15 @@ CGroundMoveType::CGroundMoveType(CUnit* owner):
nextWaypoint(ZeroVector),
atGoal(false),
haveFinalWaypoint(false),
+
+ requestedSpeed(0.0f),
currentDistanceToWaypoint(0),
+ pathRequestDelay(0),
+ numIdlingUpdates(0),
+ numIdlingSlowUpdates(0),
+
+ nextDeltaSpeedUpdate(0),
+ nextObstacleAvoidanceUpdate(0),
skidding(false),
flying(false),
@@ -130,22 +139,12 @@ CGroundMoveType::CGroundMoveType(CUnit* owner):
canReverse(owner->unitDef->rSpeed > 0.0f),
useMainHeading(false),
- skidRotVector(UpVector),
skidRotSpeed(0.0f),
+ skidRotVector(UpVector),
skidRotSpeed2(0.0f),
skidRotPos2(0.0f),
oldPhysState(CSolidObject::OnGround),
-
- flatFrontDir(0.0f, 0.0, 1.0f),
- mainHeadingPos(ZeroVector),
-
- nextDeltaSpeedUpdate(0),
- nextObstacleAvoidanceUpdate(0),
-
- pathRequestDelay(0),
-
- numIdlingUpdates(0),
- numIdlingSlowUpdates(0)
+ mainHeadingPos(0.0f, 0.0f, 0.0f)
{
if (owner) {
moveSquareX = owner->pos.x / MIN_WAYPOINT_DISTANCE;
@@ -560,17 +559,23 @@ void CGroundMoveType::ChangeHeading(short wantedHeading) {
tracefile << "unit " << owner->id << " changed heading to " << heading << " from " << _oldheading << " (wantedHeading: " << wantedHeading << ")\n";
#endif
- owner->SetDirectionFromHeading();
+ owner->frontdir = GetVectorFromHeading(heading);
+ if (owner->upright) {
+ owner->updir = UpVector;
+ owner->rightdir = owner->frontdir.cross(owner->updir);
+ } else {
+ owner->updir = ground->GetNormal(owner->pos.x, owner->pos.z);
+ owner->rightdir = owner->frontdir.cross(owner->updir);
+ owner->rightdir.Normalize();
+ owner->frontdir = owner->updir.cross(owner->rightdir);
+ }
flatFrontDir = owner->frontdir;
flatFrontDir.y = 0.0f;
flatFrontDir.Normalize();
}
-
-
-
-void CGroundMoveType::ImpulseAdded(const float3&)
+void CGroundMoveType::ImpulseAdded()
{
if (owner->beingBuilt || owner->unitDef->movedata->moveType == MoveData::Ship_Move)
return;
@@ -583,34 +588,25 @@ void CGroundMoveType::ImpulseAdded(const float3&)
impulse = ZeroVector;
}
- const float3& groundNormal = ground->GetNormal(owner->pos.x, owner->pos.z);
- const float groundImpulseScale = impulse.dot(groundNormal);
+ float3 groundNormal = ground->GetNormal(owner->pos.x, owner->pos.z);
+
+ if (impulse.dot(groundNormal) < 0)
+ impulse -= groundNormal * impulse.dot(groundNormal);
- if (groundImpulseScale < 0.0f)
- impulse -= (groundNormal * groundImpulseScale);
+ const float sqstrength = impulse.SqLength();
- if (impulse.SqLength() > 9.0f || groundImpulseScale > 0.3f) {
+ if (sqstrength > 9 || impulse.dot(groundNormal) > 0.3f) {
skidding = true;
speed += impulse;
impulse = ZeroVector;
- // FIXME: impulse should not cause a _random_ rotational component
skidRotSpeed += (gs->randFloat() - 0.5f) * 1500;
- skidRotSpeed2 = 0.0f;
- skidRotPos2 = 0.0f;
-
- float3 skidDir;
-
- if (speed.SqLength2D() >= 0.01f) {
- skidDir = speed;
- skidDir.y = 0.0f;
+ skidRotPos2 = 0;
+ skidRotSpeed2 = 0;
+ float3 skidDir(speed);
+ skidDir.y = 0;
skidDir.Normalize();
- } else {
- skidDir = owner->frontdir;
- }
-
skidRotVector = skidDir.cross(UpVector);
-
oldPhysState = owner->physicalState;
owner->physicalState = CSolidObject::Flying;
owner->moveType->useHeading = false;
@@ -690,8 +686,8 @@ void CGroundMoveType::UpdateSkid()
speed *= (speedf - speedReduction) / speedf;
}
- const float remTime = speedf / speedReduction - 1.0f;
- const float rp = floor(skidRotPos2 + skidRotSpeed2 * remTime + 0.5f);
+ float remTime = speedf / speedReduction - 1.0f;
+ float rp = floor(skidRotPos2 + skidRotSpeed2 * remTime + 0.5f);
skidRotSpeed2 = (remTime + 1.0f == 0.0f ) ? 0.0f : (rp - skidRotPos2) / (remTime + 1.0f);
@@ -720,7 +716,13 @@ void CGroundMoveType::UpdateSkid()
}
}
CalcSkidRot();
- owner->MoveMidPos(speed);
+
+ midPos += speed;
+ pos = midPos -
+ owner->frontdir * owner->relMidPos.z -
+ owner->updir * owner->relMidPos.y -
+ owner->rightdir * owner->relMidPos.x;
+ owner->midPos = midPos;
CheckCollisionSkid();
ASSERT_SYNCED_FLOAT3(owner->midPos);
@@ -733,17 +735,25 @@ void CGroundMoveType::UpdateControlledDrop()
SyncedFloat3& midPos = owner->midPos;
if (owner->falling) {
- speed.y += (mapInfo->map.gravity * owner->fallSpeed);
- speed.y = std::min(speed.y, 0.0f);
+ speed.y += mapInfo->map.gravity * owner->fallSpeed;
- owner->MoveMidPos(speed);
+ if (owner->speed.y > 0) //sometimes the dropped unit gets an upward force, still unsure where its coming from
+ owner->speed.y = 0;
- if (midPos.y < 0.0f)
- speed *= 0.90;
+ midPos += speed;
+ pos = midPos -
+ owner->frontdir * owner->relMidPos.z -
+ owner->updir * owner->relMidPos.y -
+ owner->rightdir * owner->relMidPos.x;
+
+ owner->midPos.y = owner->pos.y + owner->relMidPos.y;
+
+ if(midPos.y < 0)
+ speed*=0.90;
const float wh = GetGroundHeight(midPos);
- if (wh > (midPos.y - owner->relMidPos.y)) {
+ if (wh > midPos.y - owner->relMidPos.y) {
owner->falling = false;
midPos.y = wh + owner->relMidPos.y - speed.y * 0.8;
owner->script->Landed(); //stop parachute animation
@@ -781,8 +791,12 @@ void CGroundMoveType::CheckCollisionSkid()
const float impactSpeed = -owner->speed.dot(dif);
if (impactSpeed > 0.0f) {
- owner->MoveMidPos(dif * impactSpeed);
- owner->speed += ((dif * impactSpeed) * 1.8f);
+ midPos += dif * impactSpeed;
+ pos = midPos -
+ owner->frontdir * owner->relMidPos.z -
+ owner->updir * owner->relMidPos.y -
+ owner->rightdir * owner->relMidPos.x;
+ owner->speed += dif * (impactSpeed * 1.8f);
// damage the collider
if (impactSpeed > ownerUD->minCollisionSpeed && ownerUD->minCollisionSpeed >= 0) {
@@ -799,10 +813,17 @@ void CGroundMoveType::CheckCollisionSkid()
const float impactSpeed = (u->speed - owner->speed).dot(dif) * 0.5f;
if (impactSpeed > 0.0f) {
- owner->MoveMidPos(dif * (impactSpeed * (1 - part) * 2));
+ midPos += dif * (impactSpeed * (1 - part) * 2);
+ pos = midPos -
+ owner->frontdir * owner->relMidPos.z -
+ owner->updir * owner->relMidPos.y -
+ owner->rightdir * owner->relMidPos.x;
owner->speed += dif * (impactSpeed * (1 - part) * 2);
-
- u->MoveMidPos(dif * (impactSpeed * part * -2));
+ u->midPos -= dif * (impactSpeed * part * 2);
+ u->pos = u->midPos -
+ u->frontdir * u->relMidPos.z -
+ u->updir * u->relMidPos.y -
+ u->rightdir * u->relMidPos.x;
u->speed -= dif * (impactSpeed * part * 2);
if (CGroundMoveType* mt = dynamic_cast<CGroundMoveType*>(u->moveType)) {
@@ -845,8 +866,12 @@ void CGroundMoveType::CheckCollisionSkid()
const float impactSpeed = -owner->speed.dot(dif);
if (impactSpeed > 0.0f) {
- owner->MoveMidPos(dif * impactSpeed);
- owner->speed += ((dif * impactSpeed) * 1.8f);
+ midPos += dif * impactSpeed;
+ pos = midPos -
+ owner->frontdir * owner->relMidPos.z -
+ owner->updir * owner->relMidPos.y -
+ owner->rightdir * owner->relMidPos.x;
+ owner->speed += dif * (impactSpeed * 1.8f);
if (impactSpeed > ownerUD->minCollisionSpeed && ownerUD->minCollisionSpeed >= 0) {
owner->DoDamage(DamageArray(impactSpeed * owner->mass * 0.2f), 0, ZeroVector);
@@ -859,7 +884,18 @@ void CGroundMoveType::CheckCollisionSkid()
void CGroundMoveType::CalcSkidRot()
{
owner->heading += (short int) skidRotSpeed;
- owner->SetDirectionFromHeading();
+
+ owner->frontdir = GetVectorFromHeading(owner->heading);
+
+ if (owner->upright) {
+ owner->updir = UpVector;
+ owner->rightdir = owner->frontdir.cross(owner->updir);
+ } else {
+ owner->updir = ground->GetSmoothNormal(owner->pos.x, owner->pos.z);
+ owner->rightdir = owner->frontdir.cross(owner->updir);
+ owner->rightdir.Normalize();
+ owner->frontdir = owner->updir.cross(owner->rightdir);
+ }
skidRotPos2 += skidRotSpeed2;
@@ -868,25 +904,22 @@ void CGroundMoveType::CalcSkidRot()
float3 f1 = skidRotVector * skidRotVector.dot(owner->frontdir);
float3 f2 = owner->frontdir - f1;
+ f2 = f2 * cosp + f2.cross(skidRotVector) * sinp;
+ owner->frontdir = f1 + f2;
float3 r1 = skidRotVector * skidRotVector.dot(owner->rightdir);
float3 r2 = owner->rightdir - r1;
+ r2 = r2 * cosp + r2.cross(skidRotVector) * sinp;
+ owner->rightdir = r1 + r2;
float3 u1 = skidRotVector * skidRotVector.dot(owner->updir);
float3 u2 = owner->updir - u1;
-
- f2 = f2 * cosp + f2.cross(skidRotVector) * sinp;
- r2 = r2 * cosp + r2.cross(skidRotVector) * sinp;
u2 = u2 * cosp + u2.cross(skidRotVector) * sinp;
-
- owner->frontdir = f1 + f2;
- owner->rightdir = r1 + r2;
- owner->updir = u1 + u2;
+ owner->updir = u1 + u2;
}
-
/*
* Dynamic obstacle avoidance, helps the unit to
* follow the path even when it's not perfect.
diff --git a/rts/Sim/MoveTypes/GroundMoveType.h b/rts/Sim/MoveTypes/GroundMoveType.h
index 30ee478..ad8c805 100644
--- a/rts/Sim/MoveTypes/GroundMoveType.h
+++ b/rts/Sim/MoveTypes/GroundMoveType.h
@@ -29,7 +29,7 @@ public:
void SetMaxSpeed(float speed);
- void ImpulseAdded(const float3&);
+ void ImpulseAdded();
void KeepPointingTo(float3 pos, float distance, bool aggressive);
void KeepPointingTo(CUnit* unit, float distance, bool aggressive);
diff --git a/rts/Sim/MoveTypes/MoveType.h b/rts/Sim/MoveTypes/MoveType.h
index b89ff88..c47428c 100644
--- a/rts/Sim/MoveTypes/MoveType.h
+++ b/rts/Sim/MoveTypes/MoveType.h
@@ -23,7 +23,7 @@ public:
virtual void KeepPointingTo(float3 pos, float distance, bool aggressive) = 0;
virtual void KeepPointingTo(CUnit* unit, float distance, bool aggressive);
virtual void StopMoving() = 0;
- virtual void ImpulseAdded(const float3&) {}
+ virtual void ImpulseAdded(void) {}
virtual void ReservePad(CAirBaseHandler::LandingPad* lp);
virtual void SetGoal(const float3& pos);
diff --git a/rts/Sim/MoveTypes/ScriptMoveType.h b/rts/Sim/MoveTypes/ScriptMoveType.h
index 1195710..904fd91 100644
--- a/rts/Sim/MoveTypes/ScriptMoveType.h
+++ b/rts/Sim/MoveTypes/ScriptMoveType.h
@@ -34,6 +34,7 @@ class CScriptMoveType : public AMoveType
void KeepPointingTo(CUnit* unit, float distance, bool aggressive) {}
void StopMoving() {}
+ void ImpulseAdded() {}
void SetGoal(float3 pos) {}
void SetMaxSpeed(float speed) {}
void SetWantedMaxSpeed(float speed) {}
diff --git a/rts/Sim/Objects/SolidObject.cpp b/rts/Sim/Objects/SolidObject.cpp
index f3ec270..949f734 100644
--- a/rts/Sim/Objects/SolidObject.cpp
+++ b/rts/Sim/Objects/SolidObject.cpp
@@ -60,8 +60,8 @@ CSolidObject::CSolidObject():
isMoving(false),
isUnderWater(false),
isMarkedOnBlockingMap(false),
- speed(ZeroVector),
- residualImpulse(ZeroVector),
+ speed(0, 0, 0),
+ residualImpulse(0, 0, 0),
allyteam(0),
team(0),
mobility(NULL),
diff --git a/rts/Sim/Path/Default/PathEstimator.cpp b/rts/Sim/Path/Default/PathEstimator.cpp
index b612a2b..e64fb78 100644
--- a/rts/Sim/Path/Default/PathEstimator.cpp
+++ b/rts/Sim/Path/Default/PathEstimator.cpp
@@ -1,9 +1,6 @@
/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
#include "StdAfx.h"
-
-#include "lib/gml/gml.h" // FIXME: linux for some reason does not compile without this
-
#include "PathEstimator.h"
#include <fstream>
diff --git a/rts/Sim/Projectiles/Projectile.h b/rts/Sim/Projectiles/Projectile.h
index ab75359..b0385c1 100644
--- a/rts/Sim/Projectiles/Projectile.h
+++ b/rts/Sim/Projectiles/Projectile.h
@@ -3,7 +3,7 @@
#ifndef PROJECTILE_H
#define PROJECTILE_H
-#include "lib/gml/gml.h" // for GML_ENABLE_SIM
+#include "Rendering/GL/myGL.h"
#ifdef _MSC_VER
#pragma warning(disable:4291)
diff --git a/rts/Sim/Units/Unit.cpp b/rts/Sim/Units/Unit.cpp
index 7802b41..07ac36a 100644
--- a/rts/Sim/Units/Unit.cpp
+++ b/rts/Sim/Units/Unit.cpp
@@ -120,7 +120,6 @@ CUnit::CUnit() : CSolidObject(),
stunned(false),
useHighTrajectory(false),
dontUseWeapons(false),
- dontFire(false),
deathScriptFinished(false),
delayedWreckLevel(-1),
restTime(0),
@@ -201,6 +200,7 @@ CUnit::CUnit() : CSolidObject(),
commandShotCount(-1),
fireState(FIRESTATE_FIREATWILL),
moveState(MOVESTATE_MANEUVER),
+ dontFire(false),
activated(false),
crashing(false),
isDead(false),
@@ -233,10 +233,6 @@ CUnit::CUnit() : CSolidObject(),
myTrack(NULL),
lastFlareDrop(0),
currentFuel(0.0f),
- maxSpeed(0.0f),
- maxReverseSpeed(0.0f),
- alphaThreshold(0.1f),
- cegDamage(1),
luaDraw(false),
noDraw(false),
noSelect(false),
@@ -244,8 +240,12 @@ CUnit::CUnit() : CSolidObject(),
leaveTracks(false),
isIcon(false),
iconRadius(0.0f),
+ maxSpeed(0.0f),
+ maxReverseSpeed(0.0f),
lodCount(0),
- currentLOD(0)
+ currentLOD(0),
+ alphaThreshold(0.1f),
+ cegDamage(1)
#ifdef USE_GML
, lastDrawFrame(-30)
#endif
@@ -593,6 +593,45 @@ void CUnit::ForcedSpin(const float3& newDir)
ForcedMove(pos); // lazy, don't need to update the quadfield, etc...
}
+
+/*
+void CUnit::SetFront(const SyncedFloat3& newDir)
+{
+ frontdir = newDir;
+ frontdir.Normalize();
+ rightdir = frontdir.cross(updir);
+ rightdir.Normalize();
+ updir = rightdir.cross(frontdir);
+ updir.Normalize();
+ heading = GetHeadingFromVector(frontdir.x, frontdir.z);
+ UpdateMidPos();
+}
+
+void CUnit::SetUp(const SyncedFloat3& newDir)
+{
+ updir = newDir;
+ updir.Normalize();
+ frontdir = updir.cross(rightdir);
+ frontdir.Normalize();
+ rightdir = frontdir.cross(updir);
+ rightdir.Normalize();
+ heading = GetHeadingFromVector(frontdir.x, frontdir.z);
+ UpdateMidPos();
+}
+
+void CUnit::SetRight(const SyncedFloat3& newDir)
+{
+ rightdir = newDir;
+ rightdir.Normalize();
+ updir = rightdir.cross(frontdir);
+ updir.Normalize();
+ frontdir = updir.cross(rightdir);
+ frontdir.Normalize();
+ heading = GetHeadingFromVector(frontdir.x, frontdir.z);
+ UpdateMidPos();
+}
+*/
+
void CUnit::SetDirectionFromHeading()
{
if (GetTransporter() == NULL) {
@@ -619,14 +658,6 @@ void CUnit::UpdateMidPos()
(rightdir * relMidPos.x);
}
-void CUnit::MoveMidPos(const float3& deltaPos) {
- midPos += deltaPos;
- pos = midPos -
- (frontdir * relMidPos.z) -
- (updir * relMidPos.y) -
- (rightdir * relMidPos.x);
-}
-
void CUnit::Drop(const float3& parentPos, const float3& parentDir, CUnit* parent)
{
@@ -1054,21 +1085,18 @@ void CUnit::SlowUpdateWeapons() {
void CUnit::DoWaterDamage()
{
- if (mapInfo->water.damage <= 0.0f) {
- return;
- }
- if (!pos.IsInBounds()) {
- return;
- }
-
- const int px = pos.x / (SQUARE_SIZE * 2);
- const int pz = pos.z / (SQUARE_SIZE * 2);
- const bool isFloating = (physicalState == CSolidObject::Floating);
- const bool onGround = (physicalState == CSolidObject::OnGround);
- const bool isWaterSquare = (readmap->mipHeightmap[1][pz * gs->hmapx + px] <= 0.0f);
-
- if ((pos.y <= 0.0f) && isWaterSquare && (isFloating || onGround)) {
- DoDamage(DamageArray(mapInfo->water.damage), 0, ZeroVector, -1);
+ if (uh->waterDamage > 0.0f) {
+ if (pos.IsInBounds()) {
+ const int px = int(pos.x / (SQUARE_SIZE * 2));
+ const int pz = int(pos.z / (SQUARE_SIZE * 2));
+ const bool isFloating = (physicalState == CSolidObject::Floating);
+ const bool onGround = (physicalState == CSolidObject::OnGround);
+ const bool isWaterSquare = (readmap->mipHeightmap[1][pz * gs->hmapx + px] <= 0.0f);
+
+ if ((pos.y <= 0.0f) && isWaterSquare && (isFloating || onGround)) {
+ DoDamage(DamageArray(uh->waterDamage), 0, ZeroVector, -1);
+ }
+ }
}
}
@@ -1128,7 +1156,8 @@ void CUnit::DoDamage(const DamageArray& damages, CUnit* attacker, const float3&
damage = newDamage;
}
- AddImpulse((impulse * impulseMult) / mass);
+ residualImpulse += ((impulse * impulseMult) / mass);
+ moveType->ImpulseAdded();
if (paralyzeTime == 0) { // real damage
if (damage > 0.0f) {
@@ -1149,7 +1178,8 @@ void CUnit::DoDamage(const DamageArray& damages, CUnit* attacker, const float3&
stunned = false;
}
}
- } else { // paralyzation
+ }
+ else { // paralyzation
experienceMod *= 0.1f; // reduced experience
if (damage > 0.0f) {
// paralyzeDamage may not get higher than maxHealth * (paralyzeTime + 1),
@@ -1223,13 +1253,6 @@ void CUnit::Kill(const float3& impulse) {
DoDamage(da, NULL, impulse, -1);
}
-void CUnit::AddImpulse(const float3& addedImpulse) {
- residualImpulse += addedImpulse;
-
- if (addedImpulse.SqLength() >= 0.01f)
- moveType->ImpulseAdded(addedImpulse);
-}
-
/******************************************************************************/
diff --git a/rts/Sim/Units/Unit.h b/rts/Sim/Units/Unit.h
index 3aa74a0..31871cb 100644
--- a/rts/Sim/Units/Unit.h
+++ b/rts/Sim/Units/Unit.h
@@ -3,8 +3,6 @@
#ifndef UNIT_H
#define UNIT_H
-#include "lib/gml/gml.h" // for GML_ENABLE_SIM
-
#include <map>
#include <vector>
#include <string>
@@ -82,7 +80,6 @@ public:
const float3& impulse, int weaponId = -1);
virtual void DoWaterDamage();
virtual void Kill(const float3& impulse);
- virtual void AddImpulse(const float3&);
virtual void FinishedBuilding();
bool AttackGround(const float3& pos, bool wantDGun, bool fpsMode = false);
@@ -150,7 +147,6 @@ public:
void UpdateTerrainType();
void UpdateMidPos();
- void MoveMidPos(const float3&);
bool IsNeutral() const {
return neutral;
diff --git a/rts/Sim/Units/UnitHandler.cpp b/rts/Sim/Units/UnitHandler.cpp
index 2c8326e..ab14579 100644
--- a/rts/Sim/Units/UnitHandler.cpp
+++ b/rts/Sim/Units/UnitHandler.cpp
@@ -1,18 +1,20 @@
/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
#include "StdAfx.h"
-#include <cassert>
+#include <assert.h>
#include "mmgr.h"
#include "lib/gml/gml.h"
#include "UnitHandler.h"
#include "Unit.h"
#include "UnitDefHandler.h"
-#include "CommandAI/BuilderCAI.h"
+#include "UnitLoader.h"
#include "CommandAI/Command.h"
+#include "CommandAI/BuilderCAI.h"
#include "Game/GameSetup.h"
#include "Lua/LuaUnsyncedCtrl.h"
#include "Map/Ground.h"
+#include "Map/MapInfo.h"
#include "Map/ReadMap.h"
#include "Sim/Features/Feature.h"
#include "Sim/Features/FeatureDef.h"
@@ -27,6 +29,7 @@
#include "System/LogOutput.h"
#include "System/TimeProfiler.h"
#include "System/myMath.h"
+#include "System/LoadSave/LoadSaveInterface.h"
#include "System/Sync/SyncTracer.h"
#include "System/creg/STL_Deque.h"
#include "System/creg/STL_List.h"
@@ -39,24 +42,29 @@ using std::max;
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
-CUnitHandler* uh = NULL;
+CUnitHandler* uh;
-CR_BIND(CUnitHandler, );
+CR_BIND(CUnitHandler, (true));
CR_REG_METADATA(CUnitHandler, (
CR_MEMBER(activeUnits),
CR_MEMBER(units),
- CR_MEMBER(freeUnitIDs),
- CR_MEMBER(maxUnits),
- CR_MEMBER(maxUnitsPerTeam),
+ CR_MEMBER(freeIDs),
+ CR_MEMBER(waterDamage),
+ CR_MEMBER(unitsPerTeam),
CR_MEMBER(maxUnitRadius),
- CR_MEMBER(unitsToBeRemoved),
+ CR_MEMBER(toBeRemoved),
CR_MEMBER(morphUnitToFeature),
+// CR_MEMBER(toBeRemoved),
CR_MEMBER(builderCAIs),
CR_MEMBER(unitsByDefs),
CR_POSTLOAD(PostLoad),
CR_SERIALIZER(Serialize)
-));
+ ));
+
+void CUnitHandler::Serialize(creg::ISerializer& s)
+{
+}
void CUnitHandler::PostLoad()
@@ -66,55 +74,38 @@ void CUnitHandler::PostLoad()
}
-CUnitHandler::CUnitHandler()
+CUnitHandler::CUnitHandler(bool serializing)
:
maxUnitRadius(0.0f),
morphUnitToFeature(true)
{
- assert(teamHandler->ActiveTeams() > 0);
-
- // note: the number of active teams can change at run-time, so
- // the team unit limit should be recalculated whenever one dies
- // or spawns (but would get complicated)
- maxUnits = std::min(gameSetup->maxUnits * teamHandler->ActiveTeams(), MAX_UNITS);
- maxUnitsPerTeam = maxUnits / teamHandler->ActiveTeams();
-
- // ensure each team can make at least one unit
- assert(maxUnits >= teamHandler->ActiveTeams());
- assert(maxUnitsPerTeam >= 1);
-
- units.resize(maxUnits, NULL);
- unitsByDefs.resize(teamHandler->ActiveTeams(), std::vector<CUnitSet>(unitDefHandler->unitDefs.size()));
+ const size_t maxUnitsTemp = std::min(gameSetup->maxUnits * teamHandler->ActiveTeams(), MAX_UNITS);
+ units.resize(maxUnitsTemp);
+ unitsPerTeam = maxUnitsTemp / teamHandler->ActiveTeams() - 5;
+
+ freeIDs.reserve(units.size()-1);
+ for (size_t a = 1; a < units.size(); a++) {
+ freeIDs.push_back(a);
+ units[a] = NULL;
+ }
+ units[0] = NULL;
- {
- std::vector<unsigned int> freeIDs(units.size());
+ slowUpdateIterator = activeUnits.end();
- // id's are used as indices, so they must lie in [0, units.size() - 1]
- // (furthermore all id's are treated equally, none have special status)
- for (unsigned int id = 0; id < units.size(); id++) {
- freeIDs[id] = id;
- }
+ waterDamage = mapInfo->water.damage;
- // randomize the unit ID's so that Lua widgets can not
- // easily determine enemy unit counts from ID's alone
- // (shuffle twice for good measure)
- SyncedRNG rng;
+ if (!serializing) {
+ airBaseHandler = new CAirBaseHandler;
- std::random_shuffle(freeIDs.begin(), freeIDs.end(), rng);
- std::random_shuffle(freeIDs.begin(), freeIDs.end(), rng);
- std::copy(freeIDs.begin(), freeIDs.end(), std::front_inserter(freeUnitIDs));
+ unitsByDefs.resize(teamHandler->ActiveTeams(), std::vector<CUnitSet>(unitDefHandler->unitDefs.size()));
}
-
- slowUpdateIterator = activeUnits.end();
- airBaseHandler = new CAirBaseHandler();
}
CUnitHandler::~CUnitHandler()
{
for (std::list<CUnit*>::iterator usi = activeUnits.begin(); usi != activeUnits.end(); ++usi) {
- // ~CUnit dereferences featureHandler which is destroyed already
- (*usi)->delayedWreckLevel = -1;
+ (*usi)->delayedWreckLevel = -1; // dont create wreckages since featureHandler may be destroyed already
delete (*usi);
}
@@ -122,44 +113,40 @@ CUnitHandler::~CUnitHandler()
}
-bool CUnitHandler::AddUnit(CUnit *unit)
+int CUnitHandler::AddUnit(CUnit *unit)
{
- if (freeUnitIDs.empty()) {
- // should be unreachable (all code that goes through
- // UnitLoader::LoadUnit --> Unit::PreInit checks the
- // unit limit first)
- assert(false);
- return false;
- }
-
- unit->id = freeUnitIDs.front();
- units[unit->id] = unit;
-
+ int num = (int)(gs->randFloat()) * ((int)activeUnits.size() - 1);
std::list<CUnit*>::iterator ui = activeUnits.begin();
-
- if (ui != activeUnits.end()) {
- // randomize this to make the slow-update order random (good if one
- // builds say many buildings at once and then many mobile ones etc)
- const unsigned int insertionPos = gs->randFloat() * activeUnits.size();
-
- for (unsigned int n = 0; n < insertionPos; ++n) {
- ++ui;
- }
+ for (int a = 0; a < num;++a) {
+ ++ui;
}
+ // randomize this to make the order in slowupdate random (good if one
+ // builds say many buildings at once and then many mobile ones etc)
activeUnits.insert(ui, unit);
- freeUnitIDs.pop_front();
+ // randomize the unitID assignment so that lua widgets can
+ // not easily determine enemy unit counts from unitIDs alone
+ assert(!freeIDs.empty());
+ const unsigned int freeSlot = gs->randInt() % freeIDs.size();
+ const unsigned int freeMax = freeIDs.size() - 1;
+ unit->id = freeIDs[freeSlot]; // set the unit ID
+ freeIDs[freeSlot] = freeIDs[freeMax];
+ freeIDs.resize(freeMax);
+
+ units[unit->id] = unit;
teamHandler->Team(unit->team)->AddUnit(unit, CTeam::AddBuilt);
unitsByDefs[unit->team][unit->unitDef->id].insert(unit);
maxUnitRadius = max(unit->radius, maxUnitRadius);
- return true;
+
+ return unit->id;
}
+
void CUnitHandler::DeleteUnit(CUnit* unit)
{
- unitsToBeRemoved.push_back(unit);
+ toBeRemoved.push_back(unit);
(eventBatchHandler->GetUnitCreatedDestroyedBatch()).dequeue_synced(unit);
}
@@ -187,12 +174,13 @@ void CUnitHandler::DeleteUnitNow(CUnit* delUnit)
activeUnits.erase(usi);
units[delUnit->id] = 0;
- freeUnitIDs.push_back(delUnit->id);
+ freeIDs.push_back(delUnit->id);
teamHandler->Team(delTeam)->RemoveUnit(delUnit, CTeam::RemoveDied);
unitsByDefs[delTeam][delType].erase(delUnit);
delete delUnit;
+
break;
}
}
@@ -215,7 +203,7 @@ void CUnitHandler::Update()
{
GML_STDMUTEX_LOCK(runit); // Update
- if (!unitsToBeRemoved.empty()) {
+ if (!toBeRemoved.empty()) {
GML_RECMUTEX_LOCK(unit); // Update - for anti-deadlock purposes.
GML_RECMUTEX_LOCK(sel); // Update - unit is removed from selectedUnits in ~CObject, which is too late.
GML_RECMUTEX_LOCK(quad); // Update - make sure unit does not get partially deleted before before being removed from the quadfield
@@ -223,9 +211,9 @@ void CUnitHandler::Update()
eventHandler.DeleteSyncedUnits();
- while (!unitsToBeRemoved.empty()) {
- CUnit* delUnit = unitsToBeRemoved.back();
- unitsToBeRemoved.pop_back();
+ while (!toBeRemoved.empty()) {
+ CUnit* delUnit = toBeRemoved.back();
+ toBeRemoved.pop_back();
DeleteUnitNow(delUnit);
}
@@ -237,7 +225,7 @@ void CUnitHandler::Update()
GML_UPDATE_TICKS();
{
- SCOPED_TIMER("Unit::MoveType::Update");
+ SCOPED_TIMER("Unit Movetype update");
std::list<CUnit*>::iterator usi;
for (usi = activeUnits.begin(); usi != activeUnits.end(); ++usi) {
CUnit* unit = *usi;
@@ -252,7 +240,7 @@ void CUnitHandler::Update()
}
{
- SCOPED_TIMER("Unit::Update");
+ SCOPED_TIMER("Unit update");
std::list<CUnit*>::iterator usi;
for (usi = activeUnits.begin(); usi != activeUnits.end(); ++usi) {
CUnit* unit = *usi;
@@ -272,7 +260,7 @@ void CUnitHandler::Update()
}
{
- SCOPED_TIMER("Unit::SlowUpdate");
+ SCOPED_TIMER("Unit slow update");
if (!(gs->frameNum & (UNIT_SLOWUPDATE_RATE - 1))) {
slowUpdateIterator = activeUnits.begin();
}
@@ -285,10 +273,10 @@ void CUnitHandler::Update()
}
-float CUnitHandler::GetBuildHeight(const float3& pos, const UnitDef* unitdef)
+float CUnitHandler::GetBuildHeight(float3 pos, const UnitDef* unitdef)
{
- float minh = -5000.0f;
- float maxh = 5000.0f;
+ float minh=-5000;
+ float maxh=5000;
int numBorder=0;
float borderh=0;
const float* heightmap=readmap->GetHeightmap();
@@ -477,9 +465,10 @@ void CUnitHandler::AddBuilderCAI(CBuilderCAI* b)
{
GML_STDMUTEX_LOCK(cai); // AddBuilderCAI
- builderCAIs.insert(builderCAIs.end(), b);
+ builderCAIs.insert(builderCAIs.end(),b);
}
+
void CUnitHandler::RemoveBuilderCAI(CBuilderCAI* b)
{
GML_STDMUTEX_LOCK(cai); // RemoveBuilderCAI
@@ -488,51 +477,46 @@ void CUnitHandler::RemoveBuilderCAI(CBuilderCAI* b)
}
+void CUnitHandler::LoadSaveUnits(CLoadSaveInterface* file, bool loading)
+{
+}
+
/**
* Returns a build Command that intersects the ray described by pos and dir from
* the command queues of the units 'units' on team number 'team'.
* @brief returns a build Command that intersects the ray described by pos and dir
- * @return the build Command, or a Command with id 0 if none is found
+ * @return the build Command, or a Command wiht id 0 if none is found
*/
-Command CUnitHandler::GetBuildCommand(const float3& pos, const float3& dir) {
+Command CUnitHandler::GetBuildCommand(float3 pos, float3 dir){
float3 tempF1 = pos;
GML_STDMUTEX_LOCK(cai); // GetBuildCommand
CCommandQueue::iterator ci;
- for (std::list<CUnit*>::const_iterator ui = activeUnits.begin(); ui != activeUnits.end(); ++ui) {
- const CUnit* unit = *ui;
-
- if (unit->team != gu->myTeam) {
- continue;
- }
-
- ci = unit->commandAI->commandQue.begin();
-
- for (; ci != unit->commandAI->commandQue.end(); ++ci) {
- const Command& cmd = *ci;
-
- if (cmd.id < 0 && cmd.params.size() >= 3) {
- BuildInfo bi(cmd);
- tempF1 = pos + dir * ((bi.pos.y - pos.y) / dir.y) - bi.pos;
-
- if (bi.def && (bi.GetXSize() / 2) * SQUARE_SIZE > fabs(tempF1.x) && (bi.GetZSize() / 2) * SQUARE_SIZE > fabs(tempF1.z)) {
- return cmd;
+ for(std::list<CUnit*>::iterator ui = this->activeUnits.begin(); ui != this->activeUnits.end(); ++ui){
+ if((*ui)->team == gu->myTeam){
+ ci = (*ui)->commandAI->commandQue.begin();
+ for(; ci != (*ui)->commandAI->commandQue.end(); ++ci){
+ if((*ci).id < 0 && (*ci).params.size() >= 3){
+ BuildInfo bi(*ci);
+ tempF1 = pos + dir*((bi.pos.y - pos.y)/dir.y) - bi.pos;
+ if(bi.def && bi.GetXSize()/2*SQUARE_SIZE > fabs(tempF1.x) && bi.GetZSize()/2*SQUARE_SIZE > fabs(tempF1.z)){
+ return (*ci);
+ }
}
}
}
}
-
Command c;
- c.id = CMD_STOP;
+ c.id = 0;
return c;
}
bool CUnitHandler::CanBuildUnit(const UnitDef* unitdef, int team)
{
- if (teamHandler->Team(team)->units.size() >= maxUnitsPerTeam) {
+ if (teamHandler->Team(team)->units.size() >= unitsPerTeam) {
return false;
}
if (unitsByDefs[team][unitdef->id].size() >= unitdef->maxThisUnit) {
diff --git a/rts/Sim/Units/UnitHandler.h b/rts/Sim/Units/UnitHandler.h
index 0f348d7..407f4c7 100644
--- a/rts/Sim/Units/UnitHandler.h
+++ b/rts/Sim/Units/UnitHandler.h
@@ -24,15 +24,14 @@ class CUnitHandler
CR_DECLARE(CUnitHandler)
public:
- CUnitHandler();
- ~CUnitHandler();
-
void Update();
void DeleteUnit(CUnit* unit);
void DeleteUnitNow(CUnit* unit);
- bool AddUnit(CUnit* unit);
- void Serialize(creg::ISerializer& s) {}
+ int AddUnit(CUnit* unit);
+ CUnitHandler(bool serializing=false);
+ void Serialize(creg::ISerializer& s);
void PostLoad();
+ virtual ~CUnitHandler();
///< test if a unit can be built at specified position
///< return values for the following is
@@ -56,12 +55,20 @@ public:
void AddBuilderCAI(CBuilderCAI*);
void RemoveBuilderCAI(CBuilderCAI*);
- float GetBuildHeight(const float3& pos, const UnitDef* unitdef);
+ float GetBuildHeight(float3 pos, const UnitDef* unitdef);
+
+ void LoadSaveUnits(CLoadSaveInterface* file, bool loading);
+ Command GetBuildCommand(float3 pos, float3 dir);
- Command GetBuildCommand(const float3& pos, const float3& dir);
+ int MaxUnitsPerTeam() const
+ {
+ return unitsPerTeam;
+ };
- unsigned int MaxUnitsPerTeam() const { return maxUnitsPerTeam; }
- unsigned int MaxUnits() const { return maxUnits; }
+ size_t MaxUnits() const
+ {
+ return units.size();
+ };
// note: negative ID's are implicitly converted
@@ -72,19 +79,23 @@ public:
std::vector< std::vector<CUnitSet> > unitsByDefs; ///< units sorted by team and unitDef
std::list<CUnit*> activeUnits; ///< used to get all active units
+ std::vector<int> freeIDs;
std::vector<CUnit*> units; ///< used to get units from IDs (0 if not created)
+
+ std::vector<CUnit*> toBeRemoved; ///< units that will be removed at start of next update
+
+ std::list<CUnit*>::iterator slowUpdateIterator;
+
std::list<CBuilderCAI*> builderCAIs;
+ float waterDamage;
+
float maxUnitRadius; ///< largest radius seen so far
+
bool morphUnitToFeature;
private:
- std::list<unsigned int> freeUnitIDs;
- std::vector<CUnit*> unitsToBeRemoved; ///< units that will be removed at start of next update
- std::list<CUnit*>::iterator slowUpdateIterator;
-
- unsigned int maxUnits;
- unsigned int maxUnitsPerTeam;
+ int unitsPerTeam;
};
extern CUnitHandler* uh;
diff --git a/rts/Sim/Units/UnitLoader.cpp b/rts/Sim/Units/UnitLoader.cpp
index 47210de..fa95845 100644
--- a/rts/Sim/Units/UnitLoader.cpp
+++ b/rts/Sim/Units/UnitLoader.cpp
@@ -315,8 +315,8 @@ void CUnitLoader::GiveUnits(const std::vector<std::string>& args, int team)
}
if (objectName == "all") {
- unsigned int numRequestedUnits = unitDefHandler->unitDefs.size() - 1; /// defid=0 is not valid
- unsigned int currentNumUnits = teamHandler->Team(team)->units.size();
+ int numRequestedUnits = unitDefHandler->unitDefs.size() - 1; /// defid=0 is not valid
+ int currentNumUnits = teamHandler->Team(team)->units.size();
// make sure team unit-limit is not exceeded
if ((currentNumUnits + numRequestedUnits) > uh->MaxUnitsPerTeam()) {
@@ -345,14 +345,11 @@ void CUnitLoader::GiveUnits(const std::vector<std::string>& args, int team)
}
}
} else {
- unsigned int numRequestedUnits = amount;
- unsigned int currentNumUnits = teamHandler->Team(team)->units.size();
+ int numRequestedUnits = amount;
+ int currentNumUnits = teamHandler->Team(team)->units.size();
if (currentNumUnits >= uh->MaxUnitsPerTeam()) {
- logOutput.Print(
- "[%s] unable to give more units to team %d (current: %u, team limit: %u, global limit: %u)",
- __FUNCTION__, team, currentNumUnits, uh->MaxUnitsPerTeam(), uh->MaxUnits()
- );
+ logOutput.Print("[%s] unable to give more units to team %d (current: %d, max: %d)", __FUNCTION__, team, currentNumUnits, uh->MaxUnits());
return;
}
diff --git a/rts/Sim/Units/UnitTypes/TransportUnit.cpp b/rts/Sim/Units/UnitTypes/TransportUnit.cpp
index 72faaa3..470d6f9 100644
--- a/rts/Sim/Units/UnitTypes/TransportUnit.cpp
+++ b/rts/Sim/Units/UnitTypes/TransportUnit.cpp
@@ -77,19 +77,16 @@ void CTransportUnit::Update()
if (unitDef->holdSteady) {
// slave transportee orientation to piece
if (ti->piece >= 0) {
- const CMatrix44f& transMat = GetTransformMatrix(true);
const CMatrix44f& pieceMat = script->GetPieceMatrix(ti->piece);
- const CMatrix44f slaveMat = transMat.Mul(pieceMat);
-
- SyncedFloat3& xdir = transportee->rightdir;
- SyncedFloat3& ydir = transportee->updir;
- SyncedFloat3& zdir = transportee->frontdir;
-
- zdir.x = slaveMat[8]; zdir.y = slaveMat[9]; zdir.z = slaveMat[10];
- xdir.x = slaveMat[0]; xdir.y = slaveMat[1]; xdir.z = slaveMat[ 2];
- ydir.x = slaveMat[4]; ydir.y = slaveMat[5]; ydir.z = slaveMat[ 6];
-
- transportee->heading = GetHeadingFromVector(zdir.x, zdir.z);
+ const float3 pieceDir =
+ frontdir * pieceMat[10] +
+ updir * pieceMat[ 6] +
+ rightdir * pieceMat[ 2];
+
+ transportee->heading = GetHeadingFromVector(pieceDir.x, pieceDir.z);
+ transportee->frontdir = pieceDir;
+ transportee->rightdir = transportee->frontdir.cross(UpVector);
+ transportee->updir = transportee->rightdir.cross(transportee->frontdir);
}
} else {
// slave transportee orientation to body
diff --git a/rts/Sim/Weapons/Weapon.cpp b/rts/Sim/Weapons/Weapon.cpp
index bc60b64..aa7bf15 100644
--- a/rts/Sim/Weapons/Weapon.cpp
+++ b/rts/Sim/Weapons/Weapon.cpp
@@ -474,7 +474,7 @@ bool CWeapon::AttackGround(float3 pos, bool userTarget)
return false;
if (targetUnit) {
DeleteDeathDependence(targetUnit);
- targetUnit = NULL;
+ targetUnit=0;
}
haveUserTarget = userTarget;
@@ -531,7 +531,7 @@ bool CWeapon::AttackUnit(CUnit* unit, bool userTarget)
if (targetUnit) {
DeleteDeathDependence(targetUnit);
- targetUnit = NULL;
+ targetUnit = 0;
}
haveUserTarget = userTarget;
@@ -549,7 +549,7 @@ void CWeapon::HoldFire()
{
if (targetUnit) {
DeleteDeathDependence(targetUnit);
- targetUnit = NULL;
+ targetUnit = 0;
}
targetType = Target_None;
haveUserTarget = false;
@@ -668,7 +668,7 @@ void CWeapon::SlowUpdate(bool noAutoTargetOverride)
// use targets from the thing we are slaved to
if (targetUnit) {
DeleteDeathDependence(targetUnit);
- targetUnit = NULL;
+ targetUnit = 0;
}
targetType = Target_None;
@@ -698,34 +698,22 @@ void CWeapon::SlowUpdate(bool noAutoTargetOverride)
lastTargetRetry = gs->frameNum;
std::multimap<float, CUnit*> targets;
- std::multimap<float, CUnit*>::const_iterator nextTargetIt;
- std::multimap<float, CUnit*>::const_iterator lastTargetIt;
-
helper->GenerateWeaponTargets(this, targetUnit, targets);
- if (!targets.empty())
- lastTargetIt = --targets.end();
+ for (std::multimap<float, CUnit*>::const_iterator ti = targets.begin(); ti != targets.end(); ++ti) {
+ CUnit* nextTarget = ti->second;
- for (nextTargetIt = targets.begin(); nextTargetIt != targets.end(); ++nextTargetIt) {
- CUnit* nextTargetUnit = nextTargetIt->second;
-
- if (nextTargetUnit->neutral && (owner->fireState <= FIRESTATE_FIREATWILL)) {
+ if (nextTarget->neutral && (owner->fireState <= FIRESTATE_FIREATWILL)) {
continue;
}
-
- // when only one target is available, <nextTarget> can equal <targetUnit>
- // and we want to attack whether it is in our bad target category or not
- // (if only bad targets are available and this is the last, just pick it)
- if (nextTargetUnit != targetUnit && (nextTargetUnit->category & badTargetCategory)) {
- if (nextTargetIt != lastTargetIt) {
- continue;
- }
+ if (targetUnit && (nextTarget->category & badTargetCategory)) {
+ continue;
}
- const float weaponLead = weaponDef->targetMoveError * GAME_SPEED * nextTargetUnit->speed.Length();
+ const float weaponLead = weaponDef->targetMoveError * GAME_SPEED * nextTarget->speed.Length();
const float weaponError = weaponLead * (1.0f - owner->limExperience);
- float3 nextTargetPos = nextTargetUnit->midPos + (errorVector * weaponError);
+ float3 nextTargetPos = nextTarget->midPos + (errorVector * weaponError);
const float appHeight = ground->GetApproximateHeight(nextTargetPos.x, nextTargetPos.z) + 2.0f;
@@ -733,13 +721,13 @@ void CWeapon::SlowUpdate(bool noAutoTargetOverride)
nextTargetPos.y = appHeight;
}
- if (TryTarget(nextTargetPos, false, nextTargetUnit)) {
+ if (TryTarget(nextTargetPos, false, nextTarget)) {
if (targetUnit) {
DeleteDeathDependence(targetUnit);
}
targetType = Target_Unit;
- targetUnit = nextTargetUnit;
+ targetUnit = nextTarget;
targetPos = nextTargetPos;
AddDeathDependence(targetUnit);
@@ -755,7 +743,7 @@ void CWeapon::SlowUpdate(bool noAutoTargetOverride)
}
} else {
// if we can't target anything, try switching aim point
- if (useWeaponPosForAim == 1) {
+ if (useWeaponPosForAim && (useWeaponPosForAim == 1)) {
useWeaponPosForAim = 0;
} else {
useWeaponPosForAim = 1;