root/cafu/trunk/Libs/PlatformAux.cpp

Revision 455, 14.0 KB (checked in by Carsten, 4 months ago)

Updated copyright banners (in C++ files).

Line 
1/*
2=================================================================================
3This file is part of Cafu, the open-source game engine and graphics engine
4for multiplayer, cross-platform, real-time 3D action.
5Copyright (C) 2002-2012 Carsten Fuchs Software.
6
7Cafu is free software: you can redistribute it and/or modify it under the terms
8of the GNU General Public License as published by the Free Software Foundation,
9either version 3 of the License, or (at your option) any later version.
10
11Cafu is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
12without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13PURPOSE. See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with Cafu. If not, see <http://www.gnu.org/licenses/>.
17
18For support and more information about Cafu, visit us at <http://www.cafu.de>.
19=================================================================================
20*/
21
22#include "PlatformAux.hpp"
23#include "Templates/Array.hpp"
24#include "ConsoleCommands/Console.hpp"
25#include "FileSys/FileMan.hpp"
26#include "MaterialSystem/Renderer.hpp"
27#include "SoundSystem/SoundSys.hpp"
28
29#include <cassert>
30
31#ifdef _WIN32
32#elif __linux__
33#include <cstdio>
34#include <cstring>
35#include <dirent.h>
36#include <dlfcn.h>
37#define __stdcall
38#define GetProcAddress dlsym
39#define FreeLibrary dlclose
40#endif
41
42
43#ifdef SCONS_BUILD_DIR
44std::string PlatformAux::GetEnvFileSuffix()
45{
46    // This is just a lousy way to say that this method is obsolete with the new SCons build system!
47    return std::string("_scons");
48}
49#else
50std::string PlatformAux::GetEnvFileSuffix()
51{
52    std::string Suffix="_";
53
54#if defined(_WIN32)
55    // We are on the Win32 platform.
56    Suffix+="win32";
57
58    #if defined(__WATCOMC__)
59        // Using the OpenWatcom C/C++ compiler.
60        Suffix+="_ow";
61    #elif defined(_MSC_VER)
62        // Using the Microsoft Visual C++ compiler.
63        Suffix+="_vc60";
64    #else
65        Suffix+="_unknown";
66    #endif
67#elif __linux__ && __i386__
68    // We are on the Linux i386 platform.
69    Suffix+="li686";
70
71    #if __GNUG__    // This is equivalent to testing (__GNUC__ && __cplusplus).
72        // Using the g++ compiler.
73        // See http://www.delorie.com/gnu/docs/gcc/cpp_toc.html for documentation about the C preprocessor.
74        Suffix+="_g++";
75    #else
76        Suffix+="_unknown";
77    #endif
78#else
79    Suffix+="unknown_unknown";
80#endif
81
82#if defined(DEBUG)
83    Suffix+="_d";
84#else
85    Suffix+="_r";
86#endif
87
88    return Suffix;
89}
90#endif
91
92
93static void GetDLLs(const std::string& Path, const std::string& Prefix, ArrayT<std::string>& FoundDLLs)
94{
95    if (Path=="") return;
96
97    #if defined(_WIN32) && defined(_MSC_VER)
98    {
99        WIN32_FIND_DATA FindFileData;
100
101        HANDLE hFind=FindFirstFile((Path+"\\*").c_str(), &FindFileData);
102        if (hFind==INVALID_HANDLE_VALUE) return;
103
104        do
105        {
106            if (!_stricmp(FindFileData.cFileName, "."  )) continue;
107            if (!_stricmp(FindFileData.cFileName, ".." )) continue;
108            if (!_stricmp(FindFileData.cFileName, "cvs")) continue;
109
110            // If FindFileData.cFileName doesn't begin with Prefix, continue.
111            if (std::string(FindFileData.cFileName, Prefix.length())!=Prefix) continue;
112
113            std::string DLLName=Path+"/"+FindFileData.cFileName;
114#ifdef SCONS_BUILD_DIR
115            const std::string Suffix=".dll";
116#else
117            const std::string Suffix=GetEnvFileSuffix()+".dll"; // Console->Print("Suffix "+Suffix+", DLLName "+DLLName+"\n");
118#endif
119
120            // If FindFileData.cFileName doesn't end with Suffix, continue.
121            if (DLLName.length()<Suffix.length()) continue;
122            if (std::string(DLLName.c_str()+DLLName.length()-Suffix.length())!=Suffix) continue;
123
124            FoundDLLs.PushBack(DLLName);
125        } while (FindNextFile(hFind, &FindFileData)!=0);
126
127        if (GetLastError()==ERROR_NO_MORE_FILES) FindClose(hFind);
128    }
129    #else
130    {
131        DIR* Dir=opendir(Path.c_str());
132        if (!Dir) return;
133
134        for (dirent* DirEnt=readdir(Dir); DirEnt!=NULL; DirEnt=readdir(Dir))
135        {
136            if (!strcasecmp(DirEnt->d_name, "."  )) continue;
137            if (!strcasecmp(DirEnt->d_name, ".." )) continue;
138            if (!strcasecmp(DirEnt->d_name, "cvs")) continue;
139
140            // If FindFileData.cFileName doesn't begin with LibPrefix, continue.
141            const std::string LibPrefix="lib"+Prefix;
142            if (std::string(DirEnt->d_name, LibPrefix.length())!=LibPrefix) continue;
143
144            // For portability, only the 'd_name' member of a 'dirent' may be accessed.
145            std::string DLLName=Path+"/"+DirEnt->d_name;
146#ifdef SCONS_BUILD_DIR
147            const std::string Suffix =".so";
148#else
149            const std::string Suffix =GetEnvFileSuffix()+".dll";
150#endif
151
152            // If FindFileData.cFileName doesn't end with Suffix, continue.
153            if (DLLName.length()<Suffix.length()) continue;
154            if (std::string(DLLName.c_str()+DLLName.length()-Suffix.length())!=Suffix) continue;
155
156            FoundDLLs.PushBack(DLLName);
157        }
158
159        closedir(Dir);
160    }
161    #endif
162}
163
164
165MatSys::RendererI* PlatformAux::GetRenderer(const std::string& DLLName, HMODULE& OutRendererDLL)
166{
167    #ifdef _WIN32
168        OutRendererDLL=LoadLibrary(DLLName.c_str());
169    #else
170        // Note that RTLD_GLOBAL must *not* be passed-in here, or else we get in trouble with subsequently loaded libraries.
171        // (E.g. it causes dlsym(OutRendererDLL, "GetRenderer") to return identical results for different OutRendererDLLs.)
172        // Please refer to the man page of dlopen for more details.
173        OutRendererDLL=dlopen(DLLName.c_str(), RTLD_NOW);
174        if (!OutRendererDLL) Console->Print(std::string(dlerror()) + ", ");
175    #endif
176
177    if (!OutRendererDLL) { Console->Print("FAILED - could not load the library at "+DLLName+".\n"); return NULL; }
178
179
180    typedef MatSys::RendererI* (__stdcall *GetRendererT)(cf::ConsoleI* Console_, cf::FileSys::FileManI* FileMan_);
181
182    #if defined(_WIN32) && !defined(_WIN64)
183        GetRendererT GetRendererFunc=(GetRendererT)GetProcAddress(OutRendererDLL, "_GetRenderer@8");
184    #else
185        GetRendererT GetRendererFunc=(GetRendererT)GetProcAddress(OutRendererDLL, "GetRenderer");
186    #endif
187
188    if (!GetRendererFunc) { Console->Print("FAILED - could not get the address of the GetRenderer() function.\n"); FreeLibrary(OutRendererDLL); return NULL; }
189
190
191    // When we get here, the console and the file man must already have been initialized.
192    assert(Console!=NULL);
193    assert(cf::FileSys::FileMan!=NULL);
194
195    MatSys::RendererI* Renderer=GetRendererFunc(Console, cf::FileSys::FileMan);
196
197    if (!Renderer) { Console->Print("FAILED - could not get the renderer.\n"); FreeLibrary(OutRendererDLL); return NULL; }
198    if (!Renderer->IsSupported()) { Console->Print("FAILED - renderer says it's not supported.\n"); FreeLibrary(OutRendererDLL); return NULL; }
199
200    return Renderer;
201}
202
203
204MatSys::RendererI* PlatformAux::GetBestRenderer(HMODULE& OutRendererDLL)
205{
206#ifdef SCONS_BUILD_DIR
207    #define QUOTE(str) QUOTE_HELPER(str)
208    #define QUOTE_HELPER(str) #str
209    std::string Path=std::string("Libs/")+QUOTE(SCONS_BUILD_DIR)+"/MaterialSystem";
210    #undef QUOTE
211    #undef QUOTE_HELPER
212#else
213    std::string Path="Renderers";
214#endif
215    ArrayT<std::string> DLLNames;
216
217    Console->Print("\n");
218    Console->Print("Scanning cwd for all available renderers...\n");
219    GetDLLs(".", "Renderer", DLLNames);
220
221    if (DLLNames.Size()==0)
222    {
223        Console->Print("Scanning "+Path+" for all available renderers...\n");
224        GetDLLs(Path, "Renderer", DLLNames);
225    }
226
227
228    unsigned long BestDLLIndex= 0;      // Index into DLLNames.
229    int           BestPrefNr  =-1;      // The preference number of the renderer related to BestDLLIndex.
230
231    for (unsigned long DLLNr=0; DLLNr<DLLNames.Size(); DLLNr++)
232    {
233        Console->Print(DLLNames[DLLNr]+" ... ");
234
235        HMODULE RendererDLL;
236        MatSys::RendererI* Renderer=GetRenderer(DLLNames[DLLNr], RendererDLL);
237
238        if (!Renderer) continue;
239
240        int PrefNr=Renderer->GetPreferenceNr();
241
242        Renderer=NULL;
243        FreeLibrary(RendererDLL);
244
245        if (PrefNr<10)
246        {
247            // We don't want the Null renderer to be possibly selected for client rendering
248            // (which can happen in the presence of other errors).
249            // It would only confuse and worry users to sit in front of a black, apparently frozen screen.
250            Console->Print(cf::va("SUCCESS - but excluded from auto-selection (Pref# %i).\n", PrefNr));
251            continue;
252        }
253
254        if (PrefNr>BestPrefNr)
255        {
256            Console->Print(cf::va("SUCCESS - %s renderer (Pref# %i).\n", BestPrefNr<0 ? "first supported" : "higher preference", PrefNr));
257
258            BestDLLIndex=DLLNr;
259            BestPrefNr  =PrefNr;
260        }
261        else Console->Print(cf::va("SUCCESS - but no higher preference (Pref# %i).\n", PrefNr));
262    }
263
264    if (BestPrefNr==-1)
265    {
266        Console->Print("No renderer qualified.\n");
267        return NULL;
268    }
269
270    Console->Print("Reloading previously auto-selected renderer "+DLLNames[BestDLLIndex]+" ...\n");
271    return GetRenderer(DLLNames[BestDLLIndex], OutRendererDLL);
272}
273
274
275MatSys::TextureMapManagerI* PlatformAux::GetTextureMapManager(HMODULE RendererDLL)
276{
277    typedef MatSys::TextureMapManagerI* (__stdcall *GetTMMT)();
278
279    #if defined(_WIN32) && !defined(_WIN64)
280        GetTMMT GetTMM=(GetTMMT)GetProcAddress(RendererDLL, "_GetTextureMapManager@0");
281    #else
282        GetTMMT GetTMM=(GetTMMT)GetProcAddress(RendererDLL, "GetTextureMapManager");
283    #endif
284
285    if (!GetTMM) { Console->Print("FAILED - could not get the address of the GetTextureMapManager() function.\n"); return NULL; }
286
287    return GetTMM();
288}
289
290
291SoundSysI* PlatformAux::GetSoundSys(const std::string& DLLName, HMODULE& OutSoundSysDLL)
292{
293    #ifdef _WIN32
294        OutSoundSysDLL=LoadLibrary(DLLName.c_str());
295    #else
296        // Note that RTLD_GLOBAL must *not* be passed-in here, or else we get in trouble with subsequently loaded libraries.
297        // (E.g. it causes dlsym(OutSoundSysDLL, "GetSoundSys") to return identical results for different OutSoundSysDLLs.)
298        // Please refer to the man page of dlopen for more details.
299        OutSoundSysDLL=dlopen(DLLName.c_str(), RTLD_NOW);
300        if (!OutSoundSysDLL) Console->Print(std::string(dlerror()) + ", ");
301    #endif
302
303    if (!OutSoundSysDLL) { Console->Print("FAILED - could not load the library at "+DLLName+".\n"); return NULL; }
304
305
306    typedef SoundSysI* (__stdcall *GetSoundSys)(cf::ConsoleI* Console_, cf::FileSys::FileManI* FileMan_);
307
308    #if defined(_WIN32) && !defined(_WIN64)
309        GetSoundSys GetSoundSysFunc=(GetSoundSys)GetProcAddress(OutSoundSysDLL, "_GetSoundSys@8");
310    #else
311        GetSoundSys GetSoundSysFunc=(GetSoundSys)GetProcAddress(OutSoundSysDLL, "GetSoundSys");
312    #endif
313
314    if (!GetSoundSysFunc) { Console->Print("FAILED - could not get the address of the GetSoundSys() function.\n"); FreeLibrary(OutSoundSysDLL); return NULL; }
315
316
317    // When we get here, the console and the file man must already have been initialized.
318    assert(Console!=NULL);
319    assert(cf::FileSys::FileMan!=NULL);
320
321    SoundSysI* SoundSys=GetSoundSysFunc(Console, cf::FileSys::FileMan);
322
323    if (!SoundSys) { Console->Print("FAILED - could not get the SoundSys.\n"); FreeLibrary(OutSoundSysDLL); return NULL; }
324    if (!SoundSys->IsSupported()) { Console->Print("FAILED - SoundSys says it's not supported.\n"); FreeLibrary(OutSoundSysDLL); return NULL; }
325
326    return SoundSys;
327}
328
329
330SoundSysI* PlatformAux::GetBestSoundSys(HMODULE& OutSoundSysDLL)
331{
332#ifdef SCONS_BUILD_DIR
333    #define QUOTE(str) QUOTE_HELPER(str)
334    #define QUOTE_HELPER(str) #str
335    std::string Path=std::string("Libs/")+QUOTE(SCONS_BUILD_DIR)+"/SoundSystem";
336    #undef QUOTE
337    #undef QUOTE_HELPER
338#else
339    std::string Path="SoundSystem";
340#endif
341    ArrayT<std::string> DLLNames;
342
343    Console->Print("\n");
344    Console->Print("Scanning cwd for all available sound systems...\n");
345    GetDLLs(".", "SoundSys", DLLNames);
346
347    if (DLLNames.Size()==0)
348    {
349        Console->Print("Scanning "+Path+" for all available sound systems...\n");
350        GetDLLs(Path, "SoundSys", DLLNames);
351    }
352
353
354    unsigned long BestDLLIndex= 0;      // Index into DLLNames.
355    int           BestPrefNr  =-1;      // The preference number of the sound system related to BestDLLIndex.
356
357    for (unsigned long DLLNr=0; DLLNr<DLLNames.Size(); DLLNr++)
358    {
359        Console->Print(DLLNames[DLLNr]+" ... ");
360
361        HMODULE SoundSysDLL;
362        SoundSysI* SoundSys=GetSoundSys(DLLNames[DLLNr], SoundSysDLL);
363
364        if (!SoundSys) continue;
365
366        int PrefNr=SoundSys->GetPreferenceNr();
367
368        SoundSys=NULL;
369        FreeLibrary(SoundSysDLL);
370
371        if (PrefNr<10)
372        {
373            // We don't want the Null sound system to be possibly selected for client
374            // (which can happen in the presence of other errors).
375            // It would only confuse and worry users to sit in front of a black, apparently frozen screen.
376            Console->Print(cf::va("SUCCESS - but excluded from auto-selection (Pref# %i).\n", PrefNr));
377            continue;
378        }
379
380        if (PrefNr>BestPrefNr)
381        {
382            Console->Print(cf::va("SUCCESS - %s sound system (Pref# %i).\n", BestPrefNr<0 ? "first supported" : "higher preference", PrefNr));
383
384            BestDLLIndex=DLLNr;
385            BestPrefNr  =PrefNr;
386        }
387        else Console->Print(cf::va("SUCCESS - but no higher preference (Pref# %i).\n", PrefNr));
388    }
389
390    if (BestPrefNr==-1)
391    {
392        Console->Print("No sound system qualified.\n");
393        return NULL;
394    }
395
396    Console->Print("Reloading previously auto-selected sound system "+DLLNames[BestDLLIndex]+" ...\n");
397    return GetSoundSys(DLLNames[BestDLLIndex], OutSoundSysDLL);
398}
Note: See TracBrowser for help on using the browser.