1 /***************************************************************************
2                           trackdocument.cpp  -  All edit state data
3                              -------------------
4     begin                : do dec 12 2006
5     copyright            : (C) 2006 by CJP
6     email                : cornware-cjp@users.sourceforge.net
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #include "usmacros.h"
19 #include "timer.h"
20 
21 #include "routetracker.h"
22 
23 #include "trackdocument.h"
24 
25 CTrackDocument *theTrackDocument = NULL;
26 
CTrackDocument(CString trackname)27 CTrackDocument::CTrackDocument(CString trackname)
28 {
29 	m_CursorX = m_CursorY = m_CursorZ = 0;
30 	m_Action = NULL;
31 
32 	m_DataManager = new CTEManager;
33 	m_FutureTrack = new CEditTrack(m_DataManager);
34 
35 	m_Trackname = trackname;
36 	if(!load())
37 	{
38 		printf("Error: %s could not be loaded\n", m_Trackname.c_str());
39 		exit(1);
40 	}
41 }
42 
~CTrackDocument()43 CTrackDocument::~CTrackDocument()
44 {
45 	delete m_FutureTrack;
46 	delete m_DataManager;
47 }
48 
getCurrentTrack()49 CEditTrack *CTrackDocument::getCurrentTrack()
50 {
51 	return &(m_UndoHistory[m_UndoIndex]);
52 }
53 
getDisplayedTrack()54 CEditTrack *CTrackDocument::getDisplayedTrack()
55 {
56 	unsigned int time = (unsigned int)(4.0*CTimer().getTime());
57 
58 	if(time & 1)
59 		return m_FutureTrack;
60 
61 	return getCurrentTrack();
62 }
63 
moveCursor(int x,int y,int z)64 void CTrackDocument::moveCursor(int x, int y, int z)
65 {
66 	if(x < 0) x = 0;
67 	if(z < 0) z = 0;
68 
69 	CEditTrack *track = getCurrentTrack();
70 	if(x > track->m_L-1) x = track->m_L-1;
71 	if(z > track->m_W-1) z = track->m_W-1;
72 
73 	m_CursorX = x;
74 	m_CursorY = y;
75 	m_CursorZ = z;
76 }
77 
getCursorPos()78 CVector CTrackDocument::getCursorPos()
79 {
80 	return CVector(TILESIZE*m_CursorX, VERTSIZE*m_CursorY, TILESIZE*m_CursorZ);
81 }
82 
applyAction()83 void CTrackDocument::applyAction()
84 {
85 	if(m_FutureTrack == NULL) return;
86 
87 	//Take current track as starting point
88 	*m_FutureTrack = *getCurrentTrack();
89 
90 	if(m_Action == NULL) return;
91 	m_Action->doAction(m_FutureTrack);
92 	CRouteTracker(m_FutureTrack).trackRoutes();
93 }
94 
commitAction()95 void CTrackDocument::commitAction()
96 {
97 	//Delete future undo history
98 	while(m_UndoHistory.size() > m_UndoIndex+1)
99 		m_UndoHistory.erase(m_UndoHistory.end());
100 
101 	m_UndoHistory.push_back(*m_FutureTrack);
102 	m_UndoIndex++;
103 
104 	//Maybe the action can be done again:
105 	applyAction();
106 }
107 
undo()108 void CTrackDocument::undo()
109 {
110 	if(m_UndoIndex > 0)
111 	{
112 		m_UndoIndex--;
113 		applyAction();
114 	}
115 }
116 
redo()117 void CTrackDocument::redo()
118 {
119 	if(m_UndoIndex < m_UndoHistory.size()-1)
120 	{
121 		m_UndoIndex++;
122 		applyAction();
123 	}
124 }
125 
load()126 bool CTrackDocument::load()
127 {
128 	m_DataManager->unloadAll();
129 
130 	/*
131 	unsigned int ID = m_DataManager->loadObject(
132 		CString("tracks/") + m_Trackname,
133 		CParamList(), CDataObject::eTrack);
134 
135 	if(ID < 0) return false;
136 	*/
137 
138 	CEditTrack track(m_DataManager);
139 	if(!track.load(m_Trackname, CParamList()))
140 		return false; //loading failed
141 
142 	track.sortPillars();
143 
144 	//This will be done at the first action:
145 	//By not doing it now, we allow the user
146 	//to see the original routes.
147 	//CRouteTracker(&track).trackRoutes();
148 
149 	m_UndoHistory.clear();
150 	m_UndoHistory.push_back(track);
151 	m_UndoIndex = 0;
152 
153 	m_CursorX = m_CursorY = m_CursorZ = 0;
154 	applyAction();
155 
156 	return true;
157 }
158 
import(const CString & filename)159 bool CTrackDocument::import(const CString &filename)
160 {
161 	m_DataManager->unloadAll();
162 
163 	{
164 		CEditTrack track(m_DataManager);
165 		m_UndoHistory.clear();
166 		m_UndoHistory.push_back(track);
167 		m_UndoIndex = 0;
168 	}
169 
170 	CEditTrack *track = getCurrentTrack();
171 	if(track == NULL) return false;
172 
173 	bool ret = track->import(filename);
174 
175 	m_CursorX = m_CursorY = m_CursorZ = 0;
176 	applyAction();
177 
178 	if(ret)
179 		deleteUnusedTiles();
180 
181 	return ret;
182 }
183 
save()184 bool CTrackDocument::save()
185 {
186 	CEditTrack *track = getCurrentTrack();
187 	if(track == NULL) return false;
188 
189 	track->minimizeHeight();
190 
191 	return track->save(m_Trackname);
192 }
193 
deleteTile(int ID)194 bool CTrackDocument::deleteTile(int ID)
195 {
196 	if(ID <= 0) return false;
197 
198 	//Remove tile from tile list
199 	m_DataManager->unloadObject(CDataObject::eTileModel, ID);
200 
201 	//Get track object
202 	CEditTrack track(*getCurrentTrack());
203 
204 	//Update track array
205 	for(int i=0; i < track.m_L*track.m_W*track.m_H; i++)
206 	{
207 		STile &t = track.m_Track[i];
208 
209 		if(t.m_Model < ID) continue;
210 		if(t.m_Model == ID)
211 		{
212 			t.m_Model = 0; //empty tile
213 			continue;
214 		}
215 		t.m_Model--;
216 	}
217 
218 	//Clear undo history
219 	m_UndoHistory.clear();
220 	m_UndoHistory.push_back(track);
221 	m_UndoIndex = 0;
222 	applyAction();
223 
224 	//Remove unused textures
225 	m_DataManager->removeUnusedTextures();
226 
227 	return true;
228 }
229 
deleteUnusedTiles()230 bool CTrackDocument::deleteUnusedTiles()
231 {
232 	printf("Removing unused tiles\n");
233 
234 	unsigned int numTiles = m_DataManager->getNumObjects(CDataObject::eTileModel);
235 	if(numTiles <= 1) return true;
236 
237 	//Get track object
238 	CEditTrack track(*getCurrentTrack());
239 
240 	//Find out which tiles are used
241 	vector<bool> isUsed(numTiles, false);
242 	for(int i=0; i < track.m_L*track.m_W*track.m_H; i++)
243 	{
244 		STile &t = track.m_Track[i];
245 		isUsed[t.m_Model] = true;
246 	}
247 
248 	//Don't delete tile 0 (the empty tile)
249 	isUsed[0] = true;
250 
251 	//Delete all these tiles, from high to low to preserve later IDs in this loop
252 	for(int i=numTiles-1; i >= 1; i--)
253 	{
254 		if(!isUsed[i])
255 			m_DataManager->unloadObject(CDataObject::eTileModel, i);
256 	}
257 
258 	//Now make the ID translation table
259 	int decrease = 0;
260 	vector<int> newID(numTiles, 0);
261 	for(unsigned int i=0; i < numTiles; i++)
262 	{
263 		if(!isUsed[i]) decrease++;
264 		newID[i] = i - decrease;
265 	}
266 
267 	//And translate tile IDs
268 	for(int i=0; i < track.m_L*track.m_W*track.m_H; i++)
269 	{
270 		STile &t = track.m_Track[i];
271 		t.m_Model = newID[t.m_Model];
272 	}
273 
274 	//Clear undo history
275 	m_UndoHistory.clear();
276 	m_UndoHistory.push_back(track);
277 	m_UndoIndex = 0;
278 	applyAction();
279 
280 	//Remove unused textures
281 	m_DataManager->removeUnusedTextures();
282 
283 	return true;
284 }
285 
286