1 #include <stdio.h>
2 #include <dirent.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <unistd.h>
6 #include <string>
7 #include <map>
8 #include <TCFoundation/TCUserDefaults.h>
9 #include <TCFoundation/mystring.h>
10 #include <LDLib/LDSnapshotTaker.h>
11 #include <LDLoader/LDLModel.h>
12 #include <TCFoundation/TCAutoreleasePool.h>
13 #include <TCFoundation/TCAlertManager.h>
14 #include <TCFoundation/TCProgressAlert.h>
15 #include <TCFoundation/TCLocalStrings.h>
16 #include <GL/osmesa.h>
17 #include <TRE/TREMainModel.h>
18 #include "StudLogo.h"
19 #include "LDViewMessages.h"
20
21 typedef std::map<std::string, std::string> StringMap;
22
23 #define DEPTH_BPP 24
24 // Note: buffer contains only color buffer, not depth and stencil.
25 #define BYTES_PER_PIXEL 4
26
27 class ProgressHandler: public TCObject
28 {
29 public:
ProgressHandler(void)30 ProgressHandler(void)
31 {
32 TCAlertManager::registerHandler(TCProgressAlert::alertClass(), this,
33 (TCAlertCallback)&ProgressHandler::alertCallback);
34 }
35 protected:
~ProgressHandler(void)36 ~ProgressHandler(void)
37 {
38 }
dealloc(void)39 void dealloc(void)
40 {
41 TCAlertManager::unregisterHandler(this);
42 TCObject::dealloc();
43 }
alertCallback(TCProgressAlert * progress)44 void alertCallback(TCProgressAlert *progress)
45 {
46 if (progress->getMessage() && strlen(progress->getMessage()))
47 {
48 printf("%s: %f%%\n", progress->getMessage(),
49 progress->getProgress() * 100.0f);
50 }
51 }
52 };
53
setupDefaults(char * argv[])54 void setupDefaults(char *argv[])
55 {
56 TCUserDefaults::setCommandLine(argv);
57 // IniFile can be specified on the command line; if so, don't load a
58 // different one.
59 if (!TCUserDefaults::isIniFileSet())
60 {
61 char *homeDir = getenv("HOME");
62
63 if (homeDir)
64 {
65 char *rcFilename = copyString(homeDir, 128);
66
67 strcat(rcFilename, "/.ldviewrc");
68
69 char *rcFilename2 = copyString(homeDir, 128);
70
71 strcat(rcFilename2, "/.config/LDView/ldviewrc");
72 if (!TCUserDefaults::setIniFile(rcFilename) &&
73 !TCUserDefaults::setIniFile(rcFilename2))
74 {
75 printf("Error setting INI File to %s or %s\n", rcFilename,
76 rcFilename2);
77 }
78 delete rcFilename;
79 delete rcFilename2;
80 }
81 else
82 {
83 printf("HOME environment variable not defined: cannot use "
84 "~/.ldviewrc.\n");
85 }
86 }
87 setDebugLevel(TCUserDefaults::longForKey("DebugLevel", 0, false));
88 }
89
setupContext(OSMesaContext & ctx)90 void *setupContext(OSMesaContext &ctx)
91 {
92 void *buffer = NULL;
93 int width = TCUserDefaults::longForKey("TileWidth", 1024, false);
94 int height = TCUserDefaults::longForKey("TileHeight", 1024, false);
95 int tileSize = TCUserDefaults::longForKey("TileSize", -1, false);
96
97 if (tileSize > 0)
98 {
99 width = height = tileSize;
100 }
101 ctx = OSMesaCreateContextExt(OSMESA_RGBA, DEPTH_BPP, 8, 0, NULL);
102 if (!ctx)
103 {
104 printf("Error creating OSMesa context.\n");
105 return NULL;
106 }
107 buffer = malloc(width * height * BYTES_PER_PIXEL * sizeof(GLubyte));
108 if (OSMesaMakeCurrent(ctx, buffer, GL_UNSIGNED_BYTE, width, height))
109 {
110 GLint viewport[4] = {0};
111 glGetIntegerv(GL_VIEWPORT, viewport);
112 if (viewport[2] != width || viewport[3] != height)
113 {
114 printf("OSMesa not working!\n");
115 printf("viewport: %d, %d, %d, %d\n", (int)viewport[0],
116 (int)viewport[1], (int)viewport[2], (int)viewport[3]);
117 free(buffer);
118 buffer = NULL;
119 }
120 }
121 else
122 {
123 printf("Error attaching buffer to context.\n");
124 free(buffer);
125 buffer = NULL;
126 }
127 return buffer;
128 }
129
dirExists(const std::string & path)130 bool dirExists(const std::string &path)
131 {
132 struct stat buf;
133 if (stat(path.c_str(), &buf) != 0)
134 {
135 return false;
136 }
137 return S_ISDIR(buf.st_mode);
138 }
139
fileOrDirExists(const std::string & path)140 bool fileOrDirExists(const std::string &path)
141 {
142 struct stat buf;
143 if (stat(path.c_str(), &buf) != 0)
144 {
145 return false;
146 }
147 return S_ISREG(buf.st_mode) || S_ISDIR(buf.st_mode);
148 }
149
findDirEntry(std::string & path)150 bool findDirEntry(std::string &path)
151 {
152 size_t lastSlash = path.rfind('/');
153 if (lastSlash >= path.size())
154 {
155 return false;
156 }
157 std::string dirName = path.substr(0, lastSlash);
158 std::string lowerFilename = lowerCaseString(path.substr(lastSlash + 1));
159 DIR *dir = opendir(dirName.c_str());
160 if (dir == NULL)
161 {
162 return false;
163 }
164 bool found = false;
165 while (!found)
166 {
167 struct dirent *entry = readdir(dir);
168 if (entry == NULL)
169 {
170 break;
171 }
172 std::string name = lowerCaseString(entry->d_name);
173 if (name == lowerFilename)
174 {
175 path = dirName + '/' + entry->d_name;
176 found = true;
177 }
178 }
179 closedir(dir);
180 return found;
181 }
182
fileCaseCallback(char * filename)183 bool fileCaseCallback(char *filename)
184 {
185 StringMap s_pathMap;
186 int count;
187 char **components = componentsSeparatedByString(filename, "/", count);
188 std::string lowerFilename = lowerCaseString(filename);
189
190 StringMap::iterator it = s_pathMap.find(lowerFilename);
191 if (it != s_pathMap.end())
192 {
193 strcpy(filename, it->second.c_str());
194 return true;
195 }
196 if (count > 1)
197 {
198 bool ok = true;
199 std::string builtPath = "/";
200 for (int i = 1; i + 1 < count && ok; ++i)
201 {
202 builtPath += components[i];
203
204 it = s_pathMap.find(builtPath);
205 if (it != s_pathMap.end())
206 {
207 // Do nothing
208 }
209 else if (dirExists(builtPath))
210 {
211 s_pathMap[lowerCaseString(builtPath)] = builtPath;
212 }
213 else if (findDirEntry(builtPath))
214 {
215 s_pathMap[lowerCaseString(builtPath)] = builtPath;
216 if (!dirExists(builtPath))
217 {
218 ok = false;
219 }
220 }
221 else
222 {
223 ok = false;
224 }
225 if (ok)
226 {
227 builtPath += '/';
228 }
229 }
230 if (ok)
231 {
232 builtPath += components[count - 1];
233 if (findDirEntry(builtPath))
234 {
235 s_pathMap[lowerCaseString(builtPath)] = builtPath;
236 ok = fileOrDirExists(builtPath);
237 }
238 else
239 {
240 ok = false;
241 }
242 }
243 if (ok)
244 {
245 strcpy(filename, builtPath.c_str());
246 }
247 deleteStringArray(components, count);
248 return ok;
249 }
250 return false;
251 }
252
main(int argc,char * argv[])253 int main(int argc, char *argv[])
254 {
255 void *buffer;
256 OSMesaContext ctx;
257 int stringTableSize = sizeof(LDViewMessages_bytes);
258 char *stringTable = new char[sizeof(LDViewMessages_bytes) + 1];
259
260 memcpy(stringTable, LDViewMessages_bytes, stringTableSize);
261 stringTable[stringTableSize] = 0;
262 TCLocalStrings::setStringTable(stringTable);
263 setupDefaults(argv);
264 if ((buffer = setupContext(ctx)) != NULL)
265 {
266 //ProgressHandler *progressHandler = new ProgressHandler;
267
268 TREMainModel::setStudTextureData(StudLogo_bytes,
269 sizeof(StudLogo_bytes));
270 LDLModel::setFileCaseCallback(fileCaseCallback);
271 LDSnapshotTaker::doCommandLine();
272 OSMesaDestroyContext(ctx);
273 free(buffer);
274 //TCObject::release(progressHandler);
275 }
276 TCAutoreleasePool::processReleases();
277 return 0;
278 }
279