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