1 /*-------------------------------------------------------------------------------
2
3 BARONY
4 File: init.cpp
5 Desc: contains program initialization code
6
7 Copyright 2013-2016 (c) Turning Wheel LLC, all rights reserved.
8 See LICENSE for details.
9
10 -------------------------------------------------------------------------------*/
11
12 #include <memory>
13 #include <ctime>
14 #include <sys/stat.h>
15 #include <sstream>
16
17 #include "main.hpp"
18 #include "draw.hpp"
19 #include "files.hpp"
20 #include "sound.hpp"
21 #include "prng.hpp"
22 #include "hash.hpp"
23 #include "init.hpp"
24 #include "net.hpp"
25 #include "editor.hpp"
26 #include "menu.hpp"
27 #ifdef STEAMWORKS
28 #include <steam/steam_api.h>
29 #include "steam.hpp"
30 #endif
31 #include "player.hpp"
32 #include "items.hpp"
33 #include "cppfuncs.hpp"
34
35 #ifdef USE_FMOD
36 #include "fmod.h"
37 //#include <fmod_errors.h>
38 #endif
39
40 /*-------------------------------------------------------------------------------
41
42 initApp
43
44 initializes all the application variables and starts the engine
45
46 -------------------------------------------------------------------------------*/
47
48 #define LOADSTR1 language[741]
49 #define LOADSTR2 language[742]
50 #define LOADSTR3 language[743]
51 #define LOADSTR4 language[744]
52
53 #ifdef PANDORA
54 // Pandora FBO
55 GLuint fbo_fbo = 0;
56 GLuint fbo_tex = 0;
57 GLuint fbo_trn = 0;
58 GLuint fbo_ren = 0;
59 #endif
60
61 FILE* logfile = nullptr;
62 bool steam_init = false;
63
initApp(char const * const title,int fullscreen)64 int initApp(char const * const title, int fullscreen)
65 {
66 char name[128];
67 FILE* fp;
68 Uint32 x, c;
69
70 // open log file
71 if ( !logfile )
72 {
73 openLogFile();
74 }
75
76 for (c = 0; c < NUM_JOY_STATUS; ++c)
77 {
78 joystatus[c] = 0;
79 }
80 for (c = 0; c < NUM_JOY_TRIGGER_STATUS; ++c)
81 {
82 joy_trigger_status[c] = 0;
83 }
84
85 // init some lists
86 button_l.first = NULL;
87 button_l.last = NULL;
88 light_l.first = NULL;
89 light_l.last = NULL;
90 entitiesdeleted.first = NULL;
91 entitiesdeleted.last = NULL;
92 for ( c = 0; c < HASH_SIZE; c++ )
93 {
94 ttfTextHash[c].first = NULL;
95 ttfTextHash[c].last = NULL;
96 }
97 map.entities = NULL;
98 map.creatures = nullptr;
99 map.tiles = NULL;
100
101 // init PHYSFS
102 PHYSFS_init("/");
103 PHYSFS_permitSymbolicLinks(1);
104 if ( !PHYSFS_isInit() )
105 {
106 printlog("[PhysFS]: failed to initialize! Error code: %d", PHYSFS_getLastErrorCode());
107 return 13;
108 }
109 else
110 {
111 printlog("[PhysFS]: successfully initialized, returned: %d", PHYSFS_getLastErrorCode());
112 }
113 if ( !PHYSFS_mount(datadir, NULL, 1) )
114 {
115 printlog("[PhysFS]: unsuccessfully mounted base %s folder. Error code: %d", datadir, PHYSFS_getLastErrorCode());
116 return 13;
117 }
118 if ( PHYSFS_mount(outputdir, NULL, 1) )
119 {
120 printlog("[PhysFS]: successfully mounted output %s folder", outputdir);
121 if ( PHYSFS_setWriteDir(outputdir) )
122 {
123 PHYSFS_mkdir("savegames");
124 PHYSFS_mkdir("crashlogs");
125 PHYSFS_mkdir("logfiles");
126 PHYSFS_mkdir("data");
127 PHYSFS_mkdir("data/custom-monsters");
128 if ( PHYSFS_mkdir("mods") )
129 {
130 std::string path = outputdir;
131 path.append(PHYSFS_getDirSeparator()).append("mods");
132 PHYSFS_setWriteDir(path.c_str());
133 printlog("[PhysFS]: successfully set write folder %s", path.c_str());
134 }
135 else
136 {
137 printlog("[PhysFS]: unsuccessfully created mods/ folder. Error code: %d", PHYSFS_getLastErrorCode());
138 return 13;
139 }
140 }
141 }
142 else
143 {
144 printlog("[PhysFS]: unsuccessfully mounted base %s folder. Error code: %d", outputdir, PHYSFS_getLastErrorCode());
145 return 13;
146 }
147
148 // init steamworks
149 #ifdef STEAMWORKS
150 SteamAPI_RestartAppIfNecessary(STEAM_APPID);
151 if ( !SteamAPI_Init() )
152 {
153 printlog("error: failed to initialize Steamworks!\n");
154 printlog(" make sure your steam client is running before attempting to start again.\n");
155 return 1;
156 }
157 steam_init = true;
158 g_SteamLeaderboards = new CSteamLeaderboards();
159 g_SteamWorkshop = new CSteamWorkshop();
160 g_SteamStatistics = new CSteamStatistics(g_SteamStats, nullptr, NUM_STEAM_STATISTICS);
161 // Preloads mod content from a workshop fileID
162 //gamemodsWorkshopPreloadMod(YOUR WORKSHOP FILE ID HERE, "YOUR WORKSHOP TITLE HERE");
163 #endif
164 #if defined USE_EOS
165 EOS.readFromFile();
166 EOS.readFromCmdLineArgs();
167 if ( EOS.initPlatform(true) == false )
168 {
169 return 14;
170 }
171 #ifndef STEAMWORKS
172 #ifdef APPLE
173 if ( EOS.CredentialName.compare("") == 0 )
174 {
175 EOSFuncs::logInfo("Error, attempting to launch outside of store...");
176 return 15;
177 }
178 #else
179 if ( EOS.appRequiresRestart == EOS_EResult::EOS_Success )
180 {
181 // restarting app
182 EOSFuncs::logInfo("App attempting restart through store...");
183 return 15;
184 }
185 #endif
186 EOS.initAuth();
187 #endif // !STEAMWORKS
188 #endif
189
190 window_title = title;
191 printlog("initializing SDL...\n");
192 if ( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER ) == -1 )
193 {
194 printlog("failed to initialize SDL: %s\n", SDL_GetError());
195 return 1;
196 }
197 //printlog("initializing SDL_mixer. rate: %d format: %d channels: %d buffers: %d\n", audio_rate, audio_format, audio_channels, audio_buffers);
198 /*if( Mix_OpenAudio(audio_rate, audio_format, audio_channels, audio_buffers) ) {
199 SDL_Quit();
200 printlog("failed to initialize SDL_mixer: %s\n", Mix_GetError());
201 return 2;
202 }*/
203
204 #ifdef USE_FMOD
205 printlog("initializing FMOD...\n");
206 fmod_result = FMOD_System_Create(&fmod_system);
207 if (FMODErrorCheck())
208 {
209 printlog("Failed to create FMOD.\n");
210 no_sound = true;
211 }
212 if (!no_sound)
213 {
214 //FMOD_System_SetOutput(fmod_system, FMOD_OUTPUTTYPE_DSOUND);
215 fmod_result = FMOD_System_Init(fmod_system, fmod_maxchannels, FMOD_INIT_NORMAL | FMOD_INIT_3D_RIGHTHANDED, 0);
216 if (FMODErrorCheck())
217 {
218 printlog("Failed to initialize FMOD.\n");
219 no_sound = true;
220 }
221 if (!no_sound)
222 {
223 fmod_result = FMOD_System_CreateChannelGroup(fmod_system, NULL, &sound_group);
224 if (FMODErrorCheck())
225 {
226 printlog("Failed to create sound channel group.\n");
227 no_sound = true;
228 }
229 fmod_result = FMOD_System_CreateChannelGroup(fmod_system, NULL, &soundAmbient_group);
230 if ( FMODErrorCheck() )
231 {
232 printlog("Failed to create sound ambient channel group.\n");
233 no_sound = true;
234 }
235 fmod_result = FMOD_System_CreateChannelGroup(fmod_system, NULL, &soundEnvironment_group);
236 if ( FMODErrorCheck() )
237 {
238 printlog("Failed to create sound environment channel group.\n");
239 no_sound = true;
240 }
241 if (!no_sound)
242 {
243 fmod_result = FMOD_System_CreateChannelGroup(fmod_system, NULL, &music_group);
244 if (FMODErrorCheck())
245 {
246 printlog("Failed to create music channel group.\n");
247 no_sound = true;
248 }
249 }
250 }
251 }
252 #elif defined USE_OPENAL
253 if (!no_sound)
254 {
255 initOPENAL();
256 }
257 #endif
258 printlog("initializing SDL_net...\n");
259 if ( SDLNet_Init() < 0 )
260 {
261 printlog("failed to initialize SDL_net: %s\n", SDLNet_GetError());
262 return 2;
263 }
264 printlog("initializing SDL_image...\n");
265 if ( IMG_Init(IMG_INIT_PNG) != (IMG_INIT_PNG) )
266 {
267 printlog("failed to initialize SDL_image: %s\n", IMG_GetError());
268 return 2;
269 }
270
271 // hide cursor for game
272 if ( game )
273 {
274 SDL_ShowCursor(SDL_FALSE);
275 }
276 SDL_StopTextInput();
277
278 // initialize video
279 if ( !initVideo() )
280 {
281 return 3;
282 }
283 //SDL_EnableUNICODE(1);
284 //SDL_WM_SetCaption(title, 0);
285 //SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY,SDL_DEFAULT_REPEAT_INTERVAL);
286
287 // get pointers to opengl extensions
288 #ifdef WINDOWS
289 bool noextensions = false;
290 if ( !softwaremode )
291 {
292 if ( (SDL_glGenBuffers = (PFNGLGENBUFFERSPROC)SDL_GL_GetProcAddress("glGenBuffers")) == NULL )
293 {
294 noextensions = true;
295 }
296 else if ( (SDL_glBindBuffer = (PFNGLBINDBUFFERPROC)SDL_GL_GetProcAddress("glBindBuffer")) == NULL )
297 {
298 noextensions = true;
299 }
300 else if ( (SDL_glBufferData = (PFNGLBUFFERDATAPROC)SDL_GL_GetProcAddress("glBufferData")) == NULL )
301 {
302 noextensions = true;
303 }
304 else if ( (SDL_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)SDL_GL_GetProcAddress("glDeleteBuffers")) == NULL )
305 {
306 noextensions = true;
307 }
308 else if ( (SDL_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)SDL_GL_GetProcAddress("glGenVertexArrays")) == NULL )
309 {
310 noextensions = true;
311 }
312 else if ( (SDL_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)SDL_GL_GetProcAddress("glBindVertexArray")) == NULL )
313 {
314 noextensions = true;
315 }
316 else if ( (SDL_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)SDL_GL_GetProcAddress("glDeleteVertexArrays")) == NULL )
317 {
318 noextensions = true;
319 }
320 /*
321 // Unused
322 else if ( (SDL_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)SDL_GL_GetProcAddress("glEnableVertexAttribArray")) == NULL )
323 {
324 noextensions = true;
325 }
326 else if ( (SDL_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)SDL_GL_GetProcAddress("glVertexAttribPointer")) == NULL )
327 {
328 noextensions = true;
329 }
330 */
331 }
332 if (softwaremode)
333 {
334 printlog("notice: using software rendering.\n");
335 }
336 if ( noextensions )
337 {
338 printlog("warning: failed to load OpenGL extensions.\nYou may want to update your drivers or your graphics card, as performance will be reduced without these.\n");
339 disablevbos = true;
340 }
341 #else
342 if (softwaremode)
343 {
344 printlog("notice: using software rendering.\n");
345 }
346 #endif
347
348 // initialize buffers
349 zbuffer = (real_t*) malloc(sizeof(real_t) * xres * yres);
350 clickmap = (Entity**) malloc(sizeof(Entity*)*xres * yres);
351 texid = (GLuint*) malloc(MAXTEXTURES * sizeof(GLuint));
352 //vaoid = (GLuint *) malloc(MAXBUFFERS*sizeof(GLuint));
353 //vboid = (GLuint *) malloc(MAXBUFFERS*sizeof(GLuint));
354 allsurfaces = (SDL_Surface**) malloc(sizeof(SDL_Surface*)*MAXTEXTURES);
355 for ( c = 0; c < MAXTEXTURES; c++ )
356 {
357 allsurfaces[c] = NULL;
358 }
359 glGenTextures(MAXTEXTURES, texid);
360 //SDL_glGenVertexArrays(MAXBUFFERS, vaoid);
361 //SDL_glGenBuffers(MAXBUFFERS, vboid);
362
363 // load windows icon
364 #ifndef _MSC_VER
365 #if defined(WINDOWS) && defined(GCL_HICON)
366 HINSTANCE handle = GetModuleHandle(NULL);
367 HICON icon = LoadIcon(handle, "id");
368 if ( icon != NULL )
369 {
370 SDL_SysWMinfo wminfo;
371 SDL_VERSION( &wminfo.version );
372 if ( SDL_GetWindowWMInfo(screen, &wminfo) == SDL_TRUE )
373 {
374 HWND hwnd = wminfo.info.win.window;
375 SetClassLong(hwnd, GCL_HICON, (LONG)icon);
376 }
377 }
378 #endif
379 #endif
380
381 drawClearBuffers();
382 GO_SwapBuffers(screen);
383
384 // load resources
385 printlog("loading engine resources...\n");
386 if ((fancyWindow_bmp = loadImage("images/system/fancyWindow.png")) == NULL)
387 {
388 printlog("failed to load fancyWindow.png\n");
389 return 5;
390 }
391 if ((font8x8_bmp = loadImage("images/system/font8x8.png")) == NULL)
392 {
393 printlog("failed to load font8x8.png\n");
394 return 5;
395 }
396 if ((font12x12_bmp = loadImage("images/system/font12x12.png")) == NULL)
397 {
398 printlog("failed to load font12x12.png\n");
399 return 5;
400 }
401 if ((font16x16_bmp = loadImage("images/system/font16x16.png")) == NULL)
402 {
403 printlog("failed to load font16x16.png\n");
404 return 5;
405 }
406
407 // cache language entries
408 bool cacheText = false;
409 if (cacheText) {
410 for (int c = 0; c < NUMLANGENTRIES; ++c) {
411 bool foundSpecialChar = false;
412 for (int i = 0; language[c][i] != '\0'; ++i) {
413 if (language[c][i] == '\\' || language[c][i] == '%') {
414 foundSpecialChar = true;
415 }
416 }
417 if (foundSpecialChar) {
418 continue;
419 }
420 ttfPrintText(ttf8, 0, -200, language[c]);
421 ttfPrintText(ttf12, 0, -200, language[c]);
422 ttfPrintText(ttf16, 0, -200, language[c]);
423 }
424 }
425
426 // print a loading message
427 drawClearBuffers();
428 int w, h;
429 TTF_SizeUTF8(ttf16, LOADSTR1, &w, &h);
430 ttfPrintText(ttf16, (xres - w) / 2, (yres - h) / 2, LOADSTR1);
431
432 GO_SwapBuffers(screen);
433
434 // load sprites
435 printlog("loading sprites...\n");
436 fp = openDataFile("images/sprites.txt", "r");
437 for ( numsprites = 0; !feof(fp); numsprites++ )
438 {
439 while ( fgetc(fp) != '\n' ) if ( feof(fp) )
440 {
441 break;
442 }
443 }
444 fclose(fp);
445 if ( numsprites == 0 )
446 {
447 printlog("failed to identify any sprites in sprites.txt\n");
448 return 6;
449 }
450 sprites = (SDL_Surface**) malloc(sizeof(SDL_Surface*)*numsprites);
451 fp = openDataFile("images/sprites.txt", "r");
452 for ( c = 0; !feof(fp); c++ )
453 {
454 fscanf(fp, "%s", name);
455 while ( fgetc(fp) != '\n' ) if ( feof(fp) )
456 {
457 break;
458 }
459 sprites[c] = loadImage(name);
460 if ( sprites[c] == NULL )
461 {
462 printlog("warning: failed to load '%s' listed at line %d in sprites.txt\n", name, c + 1);
463 if ( c == 0 )
464 {
465 printlog("sprite 0 cannot be NULL!\n");
466 fclose(fp);
467 return 7;
468 }
469 }
470 }
471 fclose(fp);
472
473 // print a loading message
474 drawClearBuffers();
475 TTF_SizeUTF8(ttf16, LOADSTR2, &w, &h);
476 ttfPrintText(ttf16, (xres - w) / 2, (yres - h) / 2, LOADSTR2);
477
478 GO_SwapBuffers(screen);
479
480 // load models
481 std::string modelsDirectory = PHYSFS_getRealDir("models/models.txt");
482 modelsDirectory.append(PHYSFS_getDirSeparator()).append("models/models.txt");
483 printlog("loading models from directory %s...\n", modelsDirectory.c_str());
484
485 fp = openDataFile(modelsDirectory.c_str(), "r");
486 for ( nummodels = 0; !feof(fp); nummodels++ )
487 {
488 while ( fgetc(fp) != '\n' ) if ( feof(fp) )
489 {
490 break;
491 }
492 }
493 fclose(fp);
494 if ( nummodels == 0 )
495 {
496 printlog("failed to identify any models in models.txt\n");
497 return 11;
498 }
499 models = (voxel_t**) malloc(sizeof(voxel_t*)*nummodels);
500 fp = openDataFile(modelsDirectory.c_str(), "r");
501 for ( c = 0; !feof(fp); c++ )
502 {
503 fscanf(fp, "%s", name);
504 while ( fgetc(fp) != '\n' ) if ( feof(fp) )
505 {
506 break;
507 }
508 models[c] = loadVoxel(name);
509 if ( models[c] == NULL )
510 {
511 printlog("warning: failed to load '%s' listed at line %d in models.txt\n", name, c + 1);
512 if ( c == 0 )
513 {
514 printlog("model 0 cannot be NULL!\n");
515 fclose(fp);
516 return 12;
517 }
518 }
519 }
520 if ( !softwaremode )
521 {
522 generatePolyModels(0, nummodels, false);
523 }
524 fclose(fp);
525 // print a loading message
526 drawClearBuffers();
527 TTF_SizeUTF8(ttf16, LOADSTR3, &w, &h);
528 ttfPrintText(ttf16, (xres - w) / 2, (yres - h) / 2, LOADSTR3);
529
530 GO_SwapBuffers(screen);
531
532 // load tiles
533 std::string tilesDirectory = PHYSFS_getRealDir("images/tiles.txt");
534 tilesDirectory.append(PHYSFS_getDirSeparator()).append("images/tiles.txt");
535 printlog("loading tiles from directory %s...\n", tilesDirectory.c_str());
536
537 fp = openDataFile(tilesDirectory.c_str(), "r");
538 for ( numtiles = 0; !feof(fp); numtiles++ )
539 {
540 while ( fgetc(fp) != '\n' ) if ( feof(fp) )
541 {
542 break;
543 }
544 }
545 fclose(fp);
546 if ( numtiles == 0 )
547 {
548 printlog("failed to identify any tiles in tiles.txt\n");
549 return 8;
550 }
551 tiles = (SDL_Surface**) malloc(sizeof(SDL_Surface*)*numtiles);
552 animatedtiles = (bool*) malloc(sizeof(bool) * numtiles);
553 lavatiles = (bool*) malloc(sizeof(bool) * numtiles);
554 swimmingtiles = (bool*)malloc(sizeof(bool) * numtiles);
555 fp = openDataFile(tilesDirectory.c_str(), "r");
556 for ( c = 0; !feof(fp); c++ )
557 {
558 fscanf(fp, "%s", name);
559 while ( fgetc(fp) != '\n' ) if ( feof(fp) )
560 {
561 break;
562 }
563 tiles[c] = loadImage(name);
564 animatedtiles[c] = false;
565 lavatiles[c] = false;
566 swimmingtiles[c] = false;
567 if ( tiles[c] != NULL )
568 {
569 for (x = 0; x < strlen(name); x++)
570 {
571 if ( name[x] >= '0' && name[x] <= '9' )
572 {
573 // animated tiles if the tile name ends in a number 0-9.
574 animatedtiles[c] = true;
575 break;
576 }
577 }
578 if ( strstr(name, "Lava") || strstr(name, "lava") )
579 {
580 lavatiles[c] = true;
581 }
582 if ( strstr(name, "Water") || strstr(name, "water") || strstr(name, "swimtile") || strstr(name, "Swimtile") )
583 {
584 swimmingtiles[c] = true;
585 }
586 }
587 else
588 {
589 printlog("warning: failed to load '%s' listed at line %d in tiles.txt\n", name, c + 1);
590 if ( c == 0 )
591 {
592 printlog("tile 0 cannot be NULL!\n");
593 fclose(fp);
594 return 9;
595 }
596 }
597 }
598 fclose(fp);
599
600 // print a loading message
601 drawClearBuffers();
602 TTF_SizeUTF8(ttf16, LOADSTR4, &w, &h);
603 ttfPrintText(ttf16, (xres - w) / 2, (yres - h) / 2, LOADSTR4);
604
605 GO_SwapBuffers(screen);
606
607 // load sound effects
608 std::string soundsDirectory = PHYSFS_getRealDir("sound/sounds.txt");
609 soundsDirectory.append(PHYSFS_getDirSeparator()).append("sound/sounds.txt");
610 #ifdef USE_FMOD
611 printlog("loading sounds...\n");
612 fp = openDataFile(soundsDirectory.c_str(), "r");
613 for ( numsounds = 0; !feof(fp); numsounds++ )
614 {
615 while ( fgetc(fp) != '\n' ) if ( feof(fp) )
616 {
617 break;
618 }
619 }
620 fclose(fp);
621 if ( numsounds == 0 )
622 {
623 printlog("failed to identify any sounds in sounds.txt\n");
624 return 10;
625 }
626 sounds = (FMOD_SOUND**) malloc(sizeof(FMOD_SOUND*)*numsounds);
627 fp = openDataFile(soundsDirectory.c_str(), "r");
628 for ( c = 0; !feof(fp); c++ )
629 {
630 fscanf(fp, "%s", name);
631 while ( fgetc(fp) != '\n' ) if ( feof(fp) )
632 {
633 break;
634 }
635 //TODO: Might need to malloc the sounds[c]->sound
636 fmod_result = FMOD_System_CreateSound(fmod_system, name, (FMOD_MODE)(FMOD_SOFTWARE | FMOD_3D), NULL, &sounds[c]);
637 if (FMODErrorCheck())
638 {
639 printlog("warning: failed to load '%s' listed at line %d in sounds.txt\n", name, c + 1);
640 }
641 //TODO: set sound volume? Or otherwise handle sound volume.
642 }
643 fclose(fp);
644 FMOD_ChannelGroup_SetVolume(sound_group, sfxvolume / 128.f);
645 FMOD_ChannelGroup_SetVolume(soundAmbient_group, sfxAmbientVolume / 128.f);
646 FMOD_ChannelGroup_SetVolume(soundEnvironment_group, sfxEnvironmentVolume / 128.f);
647 FMOD_System_Set3DSettings(fmod_system, 1.0, 2.0, 1.0);
648 #elif defined USE_OPENAL
649 printlog("loading sounds...\n");
650 fp = openDataFile(soundsDirectory.c_str(), "r");
651 for ( numsounds = 0; !feof(fp); numsounds++ )
652 {
653 while ( fgetc(fp) != '\n' ) if ( feof(fp) )
654 {
655 break;
656 }
657 }
658 fclose(fp);
659 if ( numsounds == 0 )
660 {
661 printlog("failed to identify any sounds in sounds.txt\n");
662 return 10;
663 }
664 sounds = (OPENAL_BUFFER**) malloc(sizeof(OPENAL_BUFFER*)*numsounds);
665 fp = openDataFile(soundsDirectory.c_str(), "r");
666 for ( c = 0; !feof(fp); c++ )
667 {
668 fscanf(fp, "%s", name);
669 while ( fgetc(fp) != '\n' ) if ( feof(fp) )
670 {
671 break;
672 }
673 //TODO: Might need to malloc the sounds[c]->sound
674 OPENAL_CreateSound(name, true, &sounds[c]);
675 //TODO: set sound volume? Or otherwise handle sound volume.
676 }
677 fclose(fp);
678 OPENAL_ChannelGroup_SetVolume(sound_group, sfxvolume / 128.f);
679 OPENAL_ChannelGroup_SetVolume(soundAmbient_group, sfxAmbientVolume / 128.f);
680 OPENAL_ChannelGroup_SetVolume(soundEnvironment_group, sfxEnvironmentVolume / 128.f);
681 //FMOD_System_Set3DSettings(fmod_system, 1.0, 2.0, 1.0); // This on is hardcoded, I've been lazy here'
682 #endif
683 return 0;
684 }
685
686 /*-------------------------------------------------------------------------------
687
688 loadLanguage
689
690 loads the language file with the given language code in *lang
691
692 -------------------------------------------------------------------------------*/
693
loadLanguage(char const * const lang)694 int loadLanguage(char const * const lang)
695 {
696 char filename[128] = { 0 };
697 FILE* fp;
698 int c;
699
700 // open log file
701 if ( !logfile )
702 {
703 openLogFile();
704 }
705
706 // compose filename
707 snprintf(filename, 127, "lang/%s.txt", lang);
708 std::string langFilepath;
709 if ( PHYSFS_isInit() && PHYSFS_getRealDir(filename) != NULL )
710 {
711 std::string langRealDir = PHYSFS_getRealDir(filename);
712 langFilepath = langRealDir + PHYSFS_getDirSeparator() + filename;
713 }
714 else
715 {
716 langFilepath = filename;
717 }
718
719 // check if language file is valid
720 if ( !dataPathExists(langFilepath.c_str()) )
721 {
722 // language file doesn't exist
723 printlog("error: unable to locate language file: '%s'", langFilepath.c_str());
724 return 1;
725 }
726
727 // check if we've loaded this language already
728 if ( !strcmp(languageCode, lang) )
729 {
730 printlog("info: language '%s' already loaded", lang);
731 return 1;
732 }
733
734 // init SDL_TTF
735 if ( !TTF_WasInit() )
736 {
737 if ( TTF_Init() == -1 )
738 {
739 printlog("failed to initialize SDL_ttf.\n");
740 return 1;
741 }
742 }
743
744 // load fonts
745 char fontName[64] = { 0 };
746 char fontPath[1024];
747 snprintf(fontName, 63, "lang/%s.ttf", lang);
748 std::string fontFilepath;
749 if ( PHYSFS_isInit() && PHYSFS_getRealDir(fontName) != NULL )
750 {
751 std::string fontRealDir = PHYSFS_getRealDir(fontName);
752 fontFilepath = fontRealDir + PHYSFS_getDirSeparator() + fontName;
753 }
754 else
755 {
756 fontFilepath = fontName;
757 }
758
759 if ( !dataPathExists(fontFilepath.c_str()) )
760 {
761 strncpy(fontName, "lang/en.ttf", 63);
762 if ( PHYSFS_isInit() && PHYSFS_getRealDir(fontName) != NULL )
763 {
764 std::string fontRealDir = PHYSFS_getRealDir(fontName);
765 fontFilepath = fontRealDir + PHYSFS_getDirSeparator() + fontName;
766 }
767 else
768 {
769 fontFilepath = fontName;
770 }
771 }
772 if ( !dataPathExists(fontFilepath.c_str()) )
773 {
774 printlog("error: default game font 'lang/en.ttf' not found");
775 return 1;
776 }
777 completePath(fontPath, fontFilepath.c_str());
778 if ( ttf8 )
779 {
780 TTF_CloseFont(ttf8);
781 }
782 if ((ttf8 = TTF_OpenFont(fontPath, TTF8_HEIGHT)) == NULL )
783 {
784 printlog("failed to load size 8 ttf: %s\n", TTF_GetError());
785 return 1;
786 }
787 TTF_SetFontKerning(ttf8, 0);
788 TTF_SetFontHinting(ttf8, TTF_HINTING_MONO);
789 if ( ttf12 )
790 {
791 TTF_CloseFont(ttf12);
792 }
793 if ((ttf12 = TTF_OpenFont(fontPath, TTF12_HEIGHT)) == NULL )
794 {
795 printlog("failed to load size 12 ttf: %s\n", TTF_GetError());
796 return 1;
797 }
798 TTF_SetFontKerning(ttf12, 0);
799 TTF_SetFontHinting(ttf12, TTF_HINTING_MONO);
800 if ( ttf16 )
801 {
802 TTF_CloseFont(ttf16);
803 }
804 if ((ttf16 = TTF_OpenFont(fontPath, TTF16_HEIGHT)) == NULL )
805 {
806 printlog("failed to load size 16 ttf: %s\n", TTF_GetError());
807 return 1;
808 }
809 TTF_SetFontKerning(ttf16, 0);
810 TTF_SetFontHinting(ttf16, TTF_HINTING_MONO);
811
812 // open language file
813 if ( (fp = openDataFile(langFilepath.c_str(), "r")) == NULL )
814 {
815 printlog("error: unable to load language file: '%s'", langFilepath.c_str());
816 return 1;
817 }
818
819 // free currently loaded language if any
820 freeLanguages();
821
822 // store the new language code
823 strcpy(languageCode, lang);
824
825 // allocate new language strings
826 language = (char**) calloc(NUMLANGENTRIES, sizeof(char*));
827
828 // Allocate an emptry string for each possible language entry
829 for (c = 0; c < NUMLANGENTRIES; c++)
830 {
831 language[c] = (char*)calloc(1, sizeof(char));
832 }
833
834 // read file
835 Uint32 line;
836 for ( line = 1; !feof(fp); )
837 {
838 //printlog( "loading line %d...\n", line);
839 char data[1024];
840 int entry = NUMLANGENTRIES;
841 int dummy;
842
843 // read line from file
844 int i;
845 bool fileEnd = false;
846 for ( i = 0; ; i++ )
847 {
848 data[i] = fgetc(fp);
849 if ( feof(fp) )
850 {
851 fileEnd = true;
852 break;
853 }
854
855 // blank or comment lines stop reading at a newline
856 if ( data[i] == '\n' )
857 {
858 line++;
859 if ( data[0] == '\n' || data[0] == '#' )
860 {
861 break;
862 }
863 }
864 if ( data[i] == '#' )
865 {
866 if ( data[0] != '\n' && data[0] != '#' )
867 {
868 break;
869 }
870 }
871 }
872 if ( fileEnd )
873 {
874 break;
875 }
876
877 // skip blank and comment lines
878 if ( data[0] == '\n' || data[0] == '#' )
879 {
880 continue;
881 }
882
883 data[i] = 0;
884
885 // process line
886 if ( (entry = atoi(data)) == 0 )
887 {
888 printlog( "warning: syntax error in '%s':%d\n bad syntax!\n", langFilepath.c_str(), line);
889 continue;
890 }
891 else if ( entry >= NUMLANGENTRIES || entry < 0 )
892 {
893 printlog( "warning: syntax error in '%s':%d\n invalid language entry!\n", langFilepath.c_str(), line);
894 continue;
895 }
896 //printlog( "loading entry %d...\n", entry);
897 char entryText[16] = { 0 };
898 snprintf(entryText, 15, "%d", entry);
899 if ( language[entry][0] )
900 {
901 printlog( "warning: duplicate entry %d in '%s':%d\n", entry, langFilepath.c_str(), line);
902 free(language[entry]);
903 }
904 language[entry] = (char*) calloc(strlen((char*)(data + strlen(entryText) + 1)) + 1, sizeof(char));
905 strcpy(language[entry], (char*)(data + strlen(entryText) + 1));
906 }
907
908 // close file
909 fclose(fp);
910 printlog( "successfully loaded language file '%s'\n", langFilepath.c_str());
911
912 // update item internal language entries.
913 for ( int c = 0; c < NUMITEMS; ++c )
914 {
915 if ( c > SPELLBOOK_DETECT_FOOD )
916 {
917 int newItems = c - SPELLBOOK_DETECT_FOOD - 1;
918 items[c].name_identified = language[3500 + newItems * 2];
919 items[c].name_unidentified = language[3501 + newItems * 2];
920 }
921 else if ( c > ARTIFACT_BOW )
922 {
923 int newItems = c - ARTIFACT_BOW - 1;
924 items[c].name_identified = language[2200 + newItems * 2];
925 items[c].name_unidentified = language[2201 + newItems * 2];
926 }
927 else
928 {
929 items[c].name_identified = language[1545 + c * 2];
930 items[c].name_unidentified = language[1546 + c * 2];
931 }
932 }
933 initMenuOptions();
934 return 0;
935 }
936
937 /*-------------------------------------------------------------------------------
938
939 reloadLanguage
940
941 reloads the current language file
942
943 -------------------------------------------------------------------------------*/
944
reloadLanguage()945 int reloadLanguage()
946 {
947 char lang[32];
948
949 strcpy(lang, languageCode);
950 strcpy(languageCode, "");
951 return loadLanguage(lang);
952 }
953
954 /*-------------------------------------------------------------------------------
955 *
956 freeLanguages
957
958 free languages string resources
959
960 --------------------------------------------------------------------------------*/
961
freeLanguages()962 void freeLanguages()
963 {
964 int c;
965
966 if ( language )
967 {
968 for ( c = 0; c < NUMLANGENTRIES; c++ )
969 {
970 char* entry = language[c];
971 if ( entry )
972 {
973 free(entry);
974 }
975 }
976 free(language);
977 }
978 }
979
980 /*-------------------------------------------------------------------------------
981
982 generatePolyModels
983
984 processes voxel models and turns them into polygon-based models (surface
985 optimized)
986
987 -------------------------------------------------------------------------------*/
988
generatePolyModels(int start,int end,bool forceCacheRebuild)989 void generatePolyModels(int start, int end, bool forceCacheRebuild)
990 {
991 Sint32 x, y, z;
992 Sint32 c, i;
993 Uint32 index, indexdown[3];
994 Uint8 newcolor, oldcolor;
995 bool buildingquad;
996 polyquad_t* quad1, *quad2;
997 Uint32 numquads;
998 list_t quads;
999 FILE *model_cache;
1000 bool generateAll = start == 0 && end == nummodels;
1001
1002 quads.first = NULL;
1003 quads.last = NULL;
1004
1005 printlog("generating poly models...\n");
1006 if ( generateAll )
1007 {
1008 polymodels = (polymodel_t*) malloc(sizeof(polymodel_t) * nummodels);
1009 if ( useModelCache )
1010 {
1011 model_cache = openDataFile("models.cache", "rb");
1012 if ( model_cache )
1013 {
1014 char polymodelsVersionStr[7] = "v0.0.0";
1015 char modelsCacheHeader[7] = "000000";
1016 fread(&modelsCacheHeader, sizeof(char), strlen("BARONY"), model_cache);
1017
1018 if ( !strcmp(modelsCacheHeader, "BARONY") )
1019 {
1020 // we're using the new polymodels file.
1021 fread(&polymodelsVersionStr, sizeof(char), strlen(VERSION), model_cache);
1022 printlog("[MODEL CACHE]: Using updated version format %s.", polymodelsVersionStr);
1023 if ( strncmp(polymodelsVersionStr, VERSION, strlen(VERSION)) )
1024 {
1025 // different version.
1026 forceCacheRebuild = true;
1027 printlog("[MODEL CACHE]: Detected outdated version number %s - current is %s. Upgrading cache...", polymodelsVersionStr, VERSION);
1028 }
1029 }
1030 else
1031 {
1032 printlog("[MODEL CACHE]: Detected legacy cache without embedded version data, upgrading cache to %s...", VERSION);
1033 rewind(model_cache);
1034 forceCacheRebuild = true; // upgrade from legacy cache
1035 }
1036 if ( !forceCacheRebuild )
1037 {
1038 for (size_t model_index = 0; model_index < nummodels; model_index++) {
1039 polymodel_t *cur = &polymodels[model_index];
1040 fread(&cur->numfaces, sizeof(cur->numfaces), 1, model_cache);
1041 cur->faces = (polytriangle_t *) calloc(sizeof(polytriangle_t), cur->numfaces);
1042 fread(polymodels[model_index].faces, sizeof(polytriangle_t), cur->numfaces, model_cache);
1043 }
1044 fclose(model_cache);
1045 return generateVBOs(start, end);
1046 }
1047 else
1048 {
1049 fclose(model_cache);
1050 }
1051 }
1052 }
1053 }
1054
1055 for ( c = start; c < end; ++c )
1056 {
1057 char loadText[128];
1058 snprintf(loadText, 127, language[745], c, nummodels);
1059
1060 // print a loading message
1061 if ( start == 0 && end == nummodels )
1062 {
1063 if ( c % 50 == 0 )
1064 {
1065 drawClearBuffers();
1066 int w, h;
1067 TTF_SizeUTF8(ttf16, loadText, &w, &h);
1068 ttfPrintText(ttf16, (xres - w) / 2, (yres - h) / 2, loadText);
1069
1070 GO_SwapBuffers(screen);
1071 }
1072 }
1073 numquads = 0;
1074 polymodels[c].numfaces = 0;
1075 voxel_t* model = models[c];
1076 if ( !model )
1077 {
1078 continue;
1079 }
1080 indexdown[0] = model->sizez * model->sizey;
1081 indexdown[1] = model->sizez;
1082 indexdown[2] = 1;
1083
1084 // find front faces
1085 for ( x = models[c]->sizex - 1; x >= 0; x-- )
1086 {
1087 for ( z = 0; z < models[c]->sizez; z++ )
1088 {
1089 oldcolor = 255;
1090 buildingquad = false;
1091 for ( y = 0; y < models[c]->sizey; y++ )
1092 {
1093 index = z + y * models[c]->sizez + x * models[c]->sizey * models[c]->sizez;
1094 newcolor = models[c]->data[index];
1095 if ( buildingquad == true )
1096 {
1097 bool doit = false;
1098 if ( newcolor != oldcolor )
1099 {
1100 doit = true;
1101 }
1102 else if ( x < models[c]->sizex - 1 )
1103 if ( models[c]->data[index + indexdown[0]] >= 0 && models[c]->data[index + indexdown[0]] < 255 )
1104 {
1105 doit = true;
1106 }
1107 if ( doit )
1108 {
1109 // add the last two vertices to the previous quad
1110 buildingquad = false;
1111
1112 node_t* currentNode = quads.last;
1113 quad1 = (polyquad_t*)currentNode->element;
1114 quad1->vertex[1].x = x - model->sizex / 2.f + 1;
1115 quad1->vertex[1].y = y - model->sizey / 2.f;
1116 quad1->vertex[1].z = z - model->sizez / 2.f - 1;
1117 quad1->vertex[2].x = x - model->sizex / 2.f + 1;
1118 quad1->vertex[2].y = y - model->sizey / 2.f;
1119 quad1->vertex[2].z = z - model->sizez / 2.f;
1120
1121 // optimize quad
1122 node_t* node;
1123 for ( i = 0, node = quads.first; i < numquads - 1; i++, node = node->next )
1124 {
1125 quad2 = (polyquad_t*)node->element;
1126 if ( quad1->side == quad2->side )
1127 {
1128 if ( quad1->r == quad2->r && quad1->g == quad2->g && quad1->b == quad2->b )
1129 {
1130 if ( quad2->vertex[3].x == quad1->vertex[0].x && quad2->vertex[3].y == quad1->vertex[0].y && quad2->vertex[3].z == quad1->vertex[0].z )
1131 {
1132 if ( quad2->vertex[2].x == quad1->vertex[1].x && quad2->vertex[2].y == quad1->vertex[1].y && quad2->vertex[2].z == quad1->vertex[1].z )
1133 {
1134 quad2->vertex[2].z++;
1135 quad2->vertex[3].z++;
1136 list_RemoveNode(currentNode);
1137 numquads--;
1138 polymodels[c].numfaces -= 2;
1139 break;
1140 }
1141 }
1142 }
1143 }
1144 }
1145 }
1146 }
1147 if ( newcolor != oldcolor || !buildingquad )
1148 {
1149 if ( newcolor != 255 )
1150 {
1151 bool doit = false;
1152 if ( x == models[c]->sizex - 1 )
1153 {
1154 doit = true;
1155 }
1156 else if ( models[c]->data[index + indexdown[0]] == 255 )
1157 {
1158 doit = true;
1159 }
1160 if ( doit )
1161 {
1162 // start building a new quad
1163 buildingquad = true;
1164 numquads++;
1165 polymodels[c].numfaces += 2;
1166
1167 quad1 = (polyquad_t*) calloc(1, sizeof(polyquad_t));
1168 quad1->side = 0;
1169 quad1->vertex[0].x = x - model->sizex / 2.f + 1;
1170 quad1->vertex[0].y = y - model->sizey / 2.f;
1171 quad1->vertex[0].z = z - model->sizez / 2.f - 1;
1172 quad1->vertex[3].x = x - model->sizex / 2.f + 1;
1173 quad1->vertex[3].y = y - model->sizey / 2.f;
1174 quad1->vertex[3].z = z - model->sizez / 2.f;
1175 quad1->r = models[c]->palette[models[c]->data[index]][0];
1176 quad1->g = models[c]->palette[models[c]->data[index]][1];
1177 quad1->b = models[c]->palette[models[c]->data[index]][2];
1178
1179 node_t* newNode = list_AddNodeLast(&quads);
1180 newNode->element = quad1;
1181 newNode->deconstructor = &defaultDeconstructor;
1182 newNode->size = sizeof(polyquad_t);
1183 }
1184 }
1185 }
1186 oldcolor = newcolor;
1187 }
1188 if ( buildingquad == true )
1189 {
1190 // add the last two vertices to the previous quad
1191 buildingquad = false;
1192
1193 node_t* currentNode = quads.last;
1194 quad1 = (polyquad_t*)currentNode->element;
1195 quad1->vertex[1].x = x - model->sizex / 2.f + 1;
1196 quad1->vertex[1].y = y - model->sizey / 2.f;
1197 quad1->vertex[1].z = z - model->sizez / 2.f - 1;
1198 quad1->vertex[2].x = x - model->sizex / 2.f + 1;
1199 quad1->vertex[2].y = y - model->sizey / 2.f;
1200 quad1->vertex[2].z = z - model->sizez / 2.f;
1201
1202 // optimize quad
1203 node_t* node;
1204 for ( i = 0, node = quads.first; i < numquads - 1; i++, node = node->next )
1205 {
1206 quad2 = (polyquad_t*)node->element;
1207 if ( quad1->side == quad2->side )
1208 {
1209 if ( quad1->r == quad2->r && quad1->g == quad2->g && quad1->b == quad2->b )
1210 {
1211 if ( quad2->vertex[3].x == quad1->vertex[0].x && quad2->vertex[3].y == quad1->vertex[0].y && quad2->vertex[3].z == quad1->vertex[0].z )
1212 {
1213 if ( quad2->vertex[2].x == quad1->vertex[1].x && quad2->vertex[2].y == quad1->vertex[1].y && quad2->vertex[2].z == quad1->vertex[1].z )
1214 {
1215 quad2->vertex[2].z++;
1216 quad2->vertex[3].z++;
1217 list_RemoveNode(currentNode);
1218 numquads--;
1219 polymodels[c].numfaces -= 2;
1220 break;
1221 }
1222 }
1223 }
1224 }
1225 }
1226 }
1227 }
1228 }
1229
1230 // find back faces
1231 for ( x = 0; x < models[c]->sizex; x++ )
1232 {
1233 for ( z = 0; z < models[c]->sizez; z++ )
1234 {
1235 oldcolor = 255;
1236 buildingquad = false;
1237 for ( y = 0; y < models[c]->sizey; y++ )
1238 {
1239 index = z + y * models[c]->sizez + x * models[c]->sizey * models[c]->sizez;
1240 newcolor = models[c]->data[index];
1241 if ( buildingquad == true )
1242 {
1243 bool doit = false;
1244 if ( newcolor != oldcolor )
1245 {
1246 doit = true;
1247 }
1248 else if ( x > 0 )
1249 if ( models[c]->data[index - indexdown[0]] >= 0 && models[c]->data[index - indexdown[0]] < 255 )
1250 {
1251 doit = true;
1252 }
1253 if ( doit )
1254 {
1255 // add the last two vertices to the previous quad
1256 buildingquad = false;
1257
1258 node_t* currentNode = quads.last;
1259 quad1 = (polyquad_t*)currentNode->element;
1260 quad1->vertex[1].x = x - model->sizex / 2.f;
1261 quad1->vertex[1].y = y - model->sizey / 2.f;
1262 quad1->vertex[1].z = z - model->sizez / 2.f;
1263 quad1->vertex[2].x = x - model->sizex / 2.f;
1264 quad1->vertex[2].y = y - model->sizey / 2.f;
1265 quad1->vertex[2].z = z - model->sizez / 2.f - 1;
1266
1267 // optimize quad
1268 node_t* node;
1269 for ( i = 0, node = quads.first; i < numquads - 1; i++, node = node->next )
1270 {
1271 quad2 = (polyquad_t*)node->element;
1272 if ( quad1->side == quad2->side )
1273 {
1274 if ( quad1->r == quad2->r && quad1->g == quad2->g && quad1->b == quad2->b )
1275 {
1276 if ( quad2->vertex[0].x == quad1->vertex[3].x && quad2->vertex[0].y == quad1->vertex[3].y && quad2->vertex[0].z == quad1->vertex[3].z )
1277 {
1278 if ( quad2->vertex[1].x == quad1->vertex[2].x && quad2->vertex[1].y == quad1->vertex[2].y && quad2->vertex[1].z == quad1->vertex[2].z )
1279 {
1280 quad2->vertex[0].z++;
1281 quad2->vertex[1].z++;
1282 list_RemoveNode(currentNode);
1283 numquads--;
1284 polymodels[c].numfaces -= 2;
1285 break;
1286 }
1287 }
1288 }
1289 }
1290 }
1291 }
1292 }
1293 if ( newcolor != oldcolor || !buildingquad )
1294 {
1295 if ( newcolor != 255 )
1296 {
1297 bool doit = false;
1298 if ( x == 0 )
1299 {
1300 doit = true;
1301 }
1302 else if ( models[c]->data[index - indexdown[0]] == 255 )
1303 {
1304 doit = true;
1305 }
1306 if ( doit )
1307 {
1308 // start building a new quad
1309 buildingquad = true;
1310 numquads++;
1311 polymodels[c].numfaces += 2;
1312
1313 quad1 = (polyquad_t*) calloc(1, sizeof(polyquad_t));
1314 quad1->side = 1;
1315 quad1->vertex[0].x = x - model->sizex / 2.f;
1316 quad1->vertex[0].y = y - model->sizey / 2.f;
1317 quad1->vertex[0].z = z - model->sizez / 2.f;
1318 quad1->vertex[3].x = x - model->sizex / 2.f;
1319 quad1->vertex[3].y = y - model->sizey / 2.f;
1320 quad1->vertex[3].z = z - model->sizez / 2.f - 1;
1321 quad1->r = models[c]->palette[models[c]->data[index]][0];
1322 quad1->g = models[c]->palette[models[c]->data[index]][1];
1323 quad1->b = models[c]->palette[models[c]->data[index]][2];
1324
1325 node_t* newNode = list_AddNodeLast(&quads);
1326 newNode->element = quad1;
1327 newNode->deconstructor = &defaultDeconstructor;
1328 newNode->size = sizeof(polyquad_t);
1329 }
1330 }
1331 }
1332 oldcolor = newcolor;
1333 }
1334 if ( buildingquad == true )
1335 {
1336 // add the last two vertices to the previous quad
1337 buildingquad = false;
1338
1339 node_t* currentNode = quads.last;
1340 quad1 = (polyquad_t*)currentNode->element;
1341 quad1->vertex[1].x = x - model->sizex / 2.f;
1342 quad1->vertex[1].y = y - model->sizey / 2.f;
1343 quad1->vertex[1].z = z - model->sizez / 2.f;
1344 quad1->vertex[2].x = x - model->sizex / 2.f;
1345 quad1->vertex[2].y = y - model->sizey / 2.f;
1346 quad1->vertex[2].z = z - model->sizez / 2.f - 1;
1347
1348 // optimize quad
1349 node_t* node;
1350 for ( i = 0, node = quads.first; i < numquads - 1; i++, node = node->next )
1351 {
1352 quad2 = (polyquad_t*)node->element;
1353 if ( quad1->side == quad2->side )
1354 {
1355 if ( quad1->r == quad2->r && quad1->g == quad2->g && quad1->b == quad2->b )
1356 {
1357 if ( quad2->vertex[0].x == quad1->vertex[3].x && quad2->vertex[0].y == quad1->vertex[3].y && quad2->vertex[0].z == quad1->vertex[3].z )
1358 {
1359 if ( quad2->vertex[1].x == quad1->vertex[2].x && quad2->vertex[1].y == quad1->vertex[2].y && quad2->vertex[1].z == quad1->vertex[2].z )
1360 {
1361 quad2->vertex[0].z++;
1362 quad2->vertex[1].z++;
1363 list_RemoveNode(currentNode);
1364 numquads--;
1365 polymodels[c].numfaces -= 2;
1366 break;
1367 }
1368 }
1369 }
1370 }
1371 }
1372 }
1373 }
1374 }
1375
1376 // find right faces
1377 for ( y = models[c]->sizey - 1; y >= 0; y-- )
1378 {
1379 for ( z = 0; z < models[c]->sizez; z++ )
1380 {
1381 oldcolor = 255;
1382 buildingquad = false;
1383 for ( x = 0; x < models[c]->sizex; x++ )
1384 {
1385 index = z + y * models[c]->sizez + x * models[c]->sizey * models[c]->sizez;
1386 newcolor = models[c]->data[index];
1387 if ( buildingquad == true )
1388 {
1389 bool doit = false;
1390 if ( newcolor != oldcolor )
1391 {
1392 doit = true;
1393 }
1394 else if ( y < models[c]->sizey - 1 )
1395 if ( models[c]->data[index + indexdown[1]] >= 0 && models[c]->data[index + indexdown[1]] < 255 )
1396 {
1397 doit = true;
1398 }
1399 if ( doit )
1400 {
1401 // add the last two vertices to the previous quad
1402 buildingquad = false;
1403
1404 node_t* currentNode = quads.last;
1405 quad1 = (polyquad_t*) currentNode->element;
1406 quad1->vertex[1].x = x - model->sizex / 2.f;
1407 quad1->vertex[1].y = y - model->sizey / 2.f + 1;
1408 quad1->vertex[1].z = z - model->sizez / 2.f;
1409 quad1->vertex[2].x = x - model->sizex / 2.f;
1410 quad1->vertex[2].y = y - model->sizey / 2.f + 1;
1411 quad1->vertex[2].z = z - model->sizez / 2.f - 1;
1412
1413 // optimize quad
1414 node_t* node;
1415 for ( i = 0, node = quads.first; i < numquads - 1; i++, node = node->next )
1416 {
1417 quad2 = (polyquad_t*)node->element;
1418 if ( quad1->side == quad2->side )
1419 {
1420 if ( quad1->r == quad2->r && quad1->g == quad2->g && quad1->b == quad2->b )
1421 {
1422 if ( quad2->vertex[0].x == quad1->vertex[3].x && quad2->vertex[0].y == quad1->vertex[3].y && quad2->vertex[0].z == quad1->vertex[3].z )
1423 {
1424 if ( quad2->vertex[1].x == quad1->vertex[2].x && quad2->vertex[1].y == quad1->vertex[2].y && quad2->vertex[1].z == quad1->vertex[2].z )
1425 {
1426 quad2->vertex[0].z++;
1427 quad2->vertex[1].z++;
1428 list_RemoveNode(currentNode);
1429 numquads--;
1430 polymodels[c].numfaces -= 2;
1431 break;
1432 }
1433 }
1434 }
1435 }
1436 }
1437 }
1438 }
1439 if ( newcolor != oldcolor || !buildingquad )
1440 {
1441 if ( newcolor != 255 )
1442 {
1443 bool doit = false;
1444 if ( y == models[c]->sizey - 1 )
1445 {
1446 doit = true;
1447 }
1448 else if ( models[c]->data[index + indexdown[1]] == 255 )
1449 {
1450 doit = true;
1451 }
1452 if ( doit )
1453 {
1454 // start building a new quad
1455 buildingquad = true;
1456 numquads++;
1457 polymodels[c].numfaces += 2;
1458
1459 quad1 = (polyquad_t*) calloc(1, sizeof(polyquad_t));
1460 quad1->side = 2;
1461 quad1->vertex[0].x = x - model->sizex / 2.f;
1462 quad1->vertex[0].y = y - model->sizey / 2.f + 1;
1463 quad1->vertex[0].z = z - model->sizez / 2.f;
1464 quad1->vertex[3].x = x - model->sizex / 2.f;
1465 quad1->vertex[3].y = y - model->sizey / 2.f + 1;
1466 quad1->vertex[3].z = z - model->sizez / 2.f - 1;
1467 quad1->r = models[c]->palette[models[c]->data[index]][0];
1468 quad1->g = models[c]->palette[models[c]->data[index]][1];
1469 quad1->b = models[c]->palette[models[c]->data[index]][2];
1470
1471 node_t* newNode = list_AddNodeLast(&quads);
1472 newNode->element = quad1;
1473 newNode->deconstructor = &defaultDeconstructor;
1474 newNode->size = sizeof(polyquad_t);
1475 }
1476 }
1477 }
1478 oldcolor = newcolor;
1479 }
1480 if ( buildingquad == true )
1481 {
1482 // add the last two vertices to the previous quad
1483 buildingquad = false;
1484 node_t* currentNode = quads.last;
1485 quad1 = (polyquad_t*) currentNode->element;
1486 quad1->vertex[1].x = x - model->sizex / 2.f;
1487 quad1->vertex[1].y = y - model->sizey / 2.f + 1;
1488 quad1->vertex[1].z = z - model->sizez / 2.f;
1489 quad1->vertex[2].x = x - model->sizex / 2.f;
1490 quad1->vertex[2].y = y - model->sizey / 2.f + 1;
1491 quad1->vertex[2].z = z - model->sizez / 2.f - 1;
1492
1493 // optimize quad
1494 node_t* node;
1495 for ( i = 0, node = quads.first; i < numquads - 1; i++, node = node->next )
1496 {
1497 quad2 = (polyquad_t*)node->element;
1498 if ( quad1->side == quad2->side )
1499 {
1500 if ( quad1->r == quad2->r && quad1->g == quad2->g && quad1->b == quad2->b )
1501 {
1502 if ( quad2->vertex[0].x == quad1->vertex[3].x && quad2->vertex[0].y == quad1->vertex[3].y && quad2->vertex[0].z == quad1->vertex[3].z )
1503 {
1504 if ( quad2->vertex[1].x == quad1->vertex[2].x && quad2->vertex[1].y == quad1->vertex[2].y && quad2->vertex[1].z == quad1->vertex[2].z )
1505 {
1506 quad2->vertex[0].z++;
1507 quad2->vertex[1].z++;
1508 list_RemoveNode(currentNode);
1509 numquads--;
1510 polymodels[c].numfaces -= 2;
1511 break;
1512 }
1513 }
1514 }
1515 }
1516 }
1517 }
1518 }
1519 }
1520
1521 // find left faces
1522 for ( y = 0; y < models[c]->sizey; y++ )
1523 {
1524 for ( z = 0; z < models[c]->sizez; z++ )
1525 {
1526 oldcolor = 255;
1527 buildingquad = false;
1528 for ( x = 0; x < models[c]->sizex; x++ )
1529 {
1530 index = z + y * models[c]->sizez + x * models[c]->sizey * models[c]->sizez;
1531 newcolor = models[c]->data[index];
1532 if ( buildingquad == true )
1533 {
1534 bool doit = false;
1535 if ( newcolor != oldcolor )
1536 {
1537 doit = true;
1538 }
1539 else if ( y > 0 )
1540 if ( models[c]->data[index - indexdown[1]] >= 0 && models[c]->data[index - indexdown[1]] < 255 )
1541 {
1542 doit = true;
1543 }
1544 if ( doit )
1545 {
1546 // add the last two vertices to the previous quad
1547 buildingquad = false;
1548
1549 node_t* currentNode = quads.last;
1550 quad1 = (polyquad_t*) currentNode->element;
1551 quad1->vertex[1].x = x - model->sizex / 2.f;
1552 quad1->vertex[1].y = y - model->sizey / 2.f;
1553 quad1->vertex[1].z = z - model->sizez / 2.f - 1;
1554 quad1->vertex[2].x = x - model->sizex / 2.f;
1555 quad1->vertex[2].y = y - model->sizey / 2.f;
1556 quad1->vertex[2].z = z - model->sizez / 2.f;
1557
1558 // optimize quad
1559 node_t* node;
1560 for ( i = 0, node = quads.first; i < numquads - 1; i++, node = node->next )
1561 {
1562 quad2 = (polyquad_t*)node->element;
1563 if ( quad1->side == quad2->side )
1564 {
1565 if ( quad1->r == quad2->r && quad1->g == quad2->g && quad1->b == quad2->b )
1566 {
1567 if ( quad2->vertex[3].x == quad1->vertex[0].x && quad2->vertex[3].y == quad1->vertex[0].y && quad2->vertex[3].z == quad1->vertex[0].z )
1568 {
1569 if ( quad2->vertex[2].x == quad1->vertex[1].x && quad2->vertex[2].y == quad1->vertex[1].y && quad2->vertex[2].z == quad1->vertex[1].z )
1570 {
1571 quad2->vertex[2].z++;
1572 quad2->vertex[3].z++;
1573 list_RemoveNode(currentNode);
1574 numquads--;
1575 polymodels[c].numfaces -= 2;
1576 break;
1577 }
1578 }
1579 }
1580 }
1581 }
1582 }
1583 }
1584 if ( newcolor != oldcolor || !buildingquad )
1585 {
1586 if ( newcolor != 255 )
1587 {
1588 bool doit = false;
1589 if ( y == 0 )
1590 {
1591 doit = true;
1592 }
1593 else if ( models[c]->data[index - indexdown[1]] == 255 )
1594 {
1595 doit = true;
1596 }
1597 if ( doit )
1598 {
1599 // start building a new quad
1600 buildingquad = true;
1601 numquads++;
1602 polymodels[c].numfaces += 2;
1603
1604 quad1 = (polyquad_t*) calloc(1, sizeof(polyquad_t));
1605 quad1->side = 3;
1606 quad1->vertex[0].x = x - model->sizex / 2.f;
1607 quad1->vertex[0].y = y - model->sizey / 2.f;
1608 quad1->vertex[0].z = z - model->sizez / 2.f - 1;
1609 quad1->vertex[3].x = x - model->sizex / 2.f;
1610 quad1->vertex[3].y = y - model->sizey / 2.f;
1611 quad1->vertex[3].z = z - model->sizez / 2.f;
1612 quad1->r = models[c]->palette[models[c]->data[index]][0];
1613 quad1->g = models[c]->palette[models[c]->data[index]][1];
1614 quad1->b = models[c]->palette[models[c]->data[index]][2];
1615
1616 node_t* newNode = list_AddNodeLast(&quads);
1617 newNode->element = quad1;
1618 newNode->deconstructor = &defaultDeconstructor;
1619 newNode->size = sizeof(polyquad_t);
1620 }
1621 }
1622 }
1623 oldcolor = newcolor;
1624 }
1625 if ( buildingquad == true )
1626 {
1627 // add the last two vertices to the previous quad
1628 buildingquad = false;
1629 node_t* currentNode = quads.last;
1630 quad1 = (polyquad_t*) currentNode->element;
1631 quad1->vertex[1].x = x - model->sizex / 2.f;
1632 quad1->vertex[1].y = y - model->sizey / 2.f;
1633 quad1->vertex[1].z = z - model->sizez / 2.f - 1;
1634 quad1->vertex[2].x = x - model->sizex / 2.f;
1635 quad1->vertex[2].y = y - model->sizey / 2.f;
1636 quad1->vertex[2].z = z - model->sizez / 2.f;
1637
1638 // optimize quad
1639 node_t* node;
1640 for ( i = 0, node = quads.first; i < numquads - 1; i++, node = node->next )
1641 {
1642 quad2 = (polyquad_t*)node->element;
1643 if ( quad1->side == quad2->side )
1644 {
1645 if ( quad1->r == quad2->r && quad1->g == quad2->g && quad1->b == quad2->b )
1646 {
1647 if ( quad2->vertex[3].x == quad1->vertex[0].x && quad2->vertex[3].y == quad1->vertex[0].y && quad2->vertex[3].z == quad1->vertex[0].z )
1648 {
1649 if ( quad2->vertex[2].x == quad1->vertex[1].x && quad2->vertex[2].y == quad1->vertex[1].y && quad2->vertex[2].z == quad1->vertex[1].z )
1650 {
1651 quad2->vertex[2].z++;
1652 quad2->vertex[3].z++;
1653 list_RemoveNode(currentNode);
1654 numquads--;
1655 polymodels[c].numfaces -= 2;
1656 break;
1657 }
1658 }
1659 }
1660 }
1661 }
1662 }
1663 }
1664 }
1665
1666 // find bottom faces
1667 for ( z = models[c]->sizez - 1; z >= 0; z-- )
1668 {
1669 for ( y = 0; y < models[c]->sizey; y++ )
1670 {
1671 oldcolor = 255;
1672 buildingquad = false;
1673 for ( x = 0; x < models[c]->sizex; x++ )
1674 {
1675 index = z + y * models[c]->sizez + x * models[c]->sizey * models[c]->sizez;
1676 newcolor = models[c]->data[index];
1677 if ( buildingquad == true )
1678 {
1679 bool doit = false;
1680 if ( newcolor != oldcolor )
1681 {
1682 doit = true;
1683 }
1684 else if ( z < models[c]->sizez - 1 )
1685 if ( models[c]->data[index + indexdown[2]] >= 0 && models[c]->data[index + indexdown[2]] < 255 )
1686 {
1687 doit = true;
1688 }
1689 if ( doit )
1690 {
1691 // add the last two vertices to the previous quad
1692 buildingquad = false;
1693
1694 node_t* currentNode = quads.last;
1695 quad1 = (polyquad_t*) currentNode->element;
1696 quad1->vertex[1].x = x - model->sizex / 2.f;
1697 quad1->vertex[1].y = y - model->sizey / 2.f;
1698 quad1->vertex[1].z = z - model->sizez / 2.f;
1699 quad1->vertex[2].x = x - model->sizex / 2.f;
1700 quad1->vertex[2].y = y - model->sizey / 2.f + 1;
1701 quad1->vertex[2].z = z - model->sizez / 2.f;
1702
1703 // optimize quad
1704 node_t* node;
1705 for ( i = 0, node = quads.first; i < numquads - 1; i++, node = node->next )
1706 {
1707 quad2 = (polyquad_t*)node->element;
1708 if ( quad1->side == quad2->side )
1709 {
1710 if ( quad1->r == quad2->r && quad1->g == quad2->g && quad1->b == quad2->b )
1711 {
1712 if ( quad2->vertex[3].x == quad1->vertex[0].x && quad2->vertex[3].y == quad1->vertex[0].y && quad2->vertex[3].z == quad1->vertex[0].z )
1713 {
1714 if ( quad2->vertex[2].x == quad1->vertex[1].x && quad2->vertex[2].y == quad1->vertex[1].y && quad2->vertex[2].z == quad1->vertex[1].z )
1715 {
1716 quad2->vertex[2].y++;
1717 quad2->vertex[3].y++;
1718 list_RemoveNode(currentNode);
1719 numquads--;
1720 polymodels[c].numfaces -= 2;
1721 break;
1722 }
1723 }
1724 }
1725 }
1726 }
1727 }
1728 }
1729 if ( newcolor != oldcolor || !buildingquad )
1730 {
1731 if ( newcolor != 255 )
1732 {
1733 bool doit = false;
1734 if ( z == models[c]->sizez - 1 )
1735 {
1736 doit = true;
1737 }
1738 else if ( models[c]->data[index + indexdown[2]] == 255 )
1739 {
1740 doit = true;
1741 }
1742 if ( doit )
1743 {
1744 // start building a new quad
1745 buildingquad = true;
1746 numquads++;
1747 polymodels[c].numfaces += 2;
1748
1749 quad1 = (polyquad_t*) calloc(1, sizeof(polyquad_t));
1750 quad1->side = 4;
1751 quad1->vertex[0].x = x - model->sizex / 2.f;
1752 quad1->vertex[0].y = y - model->sizey / 2.f;
1753 quad1->vertex[0].z = z - model->sizez / 2.f;
1754 quad1->vertex[3].x = x - model->sizex / 2.f;
1755 quad1->vertex[3].y = y - model->sizey / 2.f + 1;
1756 quad1->vertex[3].z = z - model->sizez / 2.f;
1757 quad1->r = models[c]->palette[models[c]->data[index]][0];
1758 quad1->g = models[c]->palette[models[c]->data[index]][1];
1759 quad1->b = models[c]->palette[models[c]->data[index]][2];
1760
1761 node_t* newNode = list_AddNodeLast(&quads);
1762 newNode->element = quad1;
1763 newNode->deconstructor = &defaultDeconstructor;
1764 newNode->size = sizeof(polyquad_t);
1765 }
1766 }
1767 }
1768 oldcolor = newcolor;
1769 }
1770 if ( buildingquad == true )
1771 {
1772 // add the last two vertices to the previous quad
1773 buildingquad = false;
1774
1775 node_t* currentNode = quads.last;
1776 quad1 = (polyquad_t*) currentNode->element;
1777 quad1->vertex[1].x = x - model->sizex / 2.f;
1778 quad1->vertex[1].y = y - model->sizey / 2.f;
1779 quad1->vertex[1].z = z - model->sizez / 2.f;
1780 quad1->vertex[2].x = x - model->sizex / 2.f;
1781 quad1->vertex[2].y = y - model->sizey / 2.f + 1;
1782 quad1->vertex[2].z = z - model->sizez / 2.f;
1783
1784 // optimize quad
1785 node_t* node;
1786 for ( i = 0, node = quads.first; i < numquads - 1; i++, node = node->next )
1787 {
1788 quad2 = (polyquad_t*)node->element;
1789 if ( quad1->side == quad2->side )
1790 {
1791 if ( quad1->r == quad2->r && quad1->g == quad2->g && quad1->b == quad2->b )
1792 {
1793 if ( quad2->vertex[3].x == quad1->vertex[0].x && quad2->vertex[3].y == quad1->vertex[0].y && quad2->vertex[3].z == quad1->vertex[0].z )
1794 {
1795 if ( quad2->vertex[2].x == quad1->vertex[1].x && quad2->vertex[2].y == quad1->vertex[1].y && quad2->vertex[2].z == quad1->vertex[1].z )
1796 {
1797 quad2->vertex[2].y++;
1798 quad2->vertex[3].y++;
1799 list_RemoveNode(currentNode);
1800 numquads--;
1801 polymodels[c].numfaces -= 2;
1802 break;
1803 }
1804 }
1805 }
1806 }
1807 }
1808 }
1809 }
1810 }
1811
1812 // find top faces
1813 for ( z = 0; z < models[c]->sizez; z++ )
1814 {
1815 for ( y = 0; y < models[c]->sizey; y++ )
1816 {
1817 oldcolor = 255;
1818 buildingquad = false;
1819 for ( x = 0; x < models[c]->sizex; x++ )
1820 {
1821 index = z + y * models[c]->sizez + x * models[c]->sizey * models[c]->sizez;
1822 newcolor = models[c]->data[index];
1823 if ( buildingquad == true )
1824 {
1825 bool doit = false;
1826 if ( newcolor != oldcolor )
1827 {
1828 doit = true;
1829 }
1830 else if ( z > 0 )
1831 if ( models[c]->data[index - indexdown[2]] >= 0 && models[c]->data[index - indexdown[2]] < 255 )
1832 {
1833 doit = true;
1834 }
1835 if ( doit )
1836 {
1837 // add the last two vertices to the previous quad
1838 buildingquad = false;
1839
1840 node_t* currentNode = quads.last;
1841 quad1 = (polyquad_t*) currentNode->element;
1842 quad1->vertex[1].x = x - model->sizex / 2.f;
1843 quad1->vertex[1].y = y - model->sizey / 2.f + 1;
1844 quad1->vertex[1].z = z - model->sizez / 2.f - 1;
1845 quad1->vertex[2].x = x - model->sizex / 2.f;
1846 quad1->vertex[2].y = y - model->sizey / 2.f;
1847 quad1->vertex[2].z = z - model->sizez / 2.f - 1;
1848
1849 // optimize quad
1850 node_t* node;
1851 for ( i = 0, node = quads.first; i < numquads - 1; i++, node = node->next )
1852 {
1853 quad2 = (polyquad_t*)node->element;
1854 if ( quad1->side == quad2->side )
1855 {
1856 if ( quad1->r == quad2->r && quad1->g == quad2->g && quad1->b == quad2->b )
1857 {
1858 if ( quad2->vertex[0].x == quad1->vertex[3].x && quad2->vertex[0].y == quad1->vertex[3].y && quad2->vertex[0].z == quad1->vertex[3].z )
1859 {
1860 if ( quad2->vertex[1].x == quad1->vertex[2].x && quad2->vertex[1].y == quad1->vertex[2].y && quad2->vertex[1].z == quad1->vertex[2].z )
1861 {
1862 quad2->vertex[0].y++;
1863 quad2->vertex[1].y++;
1864 list_RemoveNode(currentNode);
1865 numquads--;
1866 polymodels[c].numfaces -= 2;
1867 break;
1868 }
1869 }
1870 }
1871 }
1872 }
1873 }
1874 }
1875 if ( newcolor != oldcolor || !buildingquad )
1876 {
1877 if ( newcolor != 255 )
1878 {
1879 bool doit = false;
1880 if ( z == 0 )
1881 {
1882 doit = true;
1883 }
1884 else if ( models[c]->data[index - indexdown[2]] == 255 )
1885 {
1886 doit = true;
1887 }
1888 if ( doit )
1889 {
1890 // start building a new quad
1891 buildingquad = true;
1892 numquads++;
1893 polymodels[c].numfaces += 2;
1894
1895 quad1 = (polyquad_t*) calloc(1, sizeof(polyquad_t));
1896 quad1->side = 5;
1897 quad1->vertex[0].x = x - model->sizex / 2.f;
1898 quad1->vertex[0].y = y - model->sizey / 2.f + 1;
1899 quad1->vertex[0].z = z - model->sizez / 2.f - 1;
1900 quad1->vertex[3].x = x - model->sizex / 2.f;
1901 quad1->vertex[3].y = y - model->sizey / 2.f;
1902 quad1->vertex[3].z = z - model->sizez / 2.f - 1;
1903 quad1->r = models[c]->palette[models[c]->data[index]][0];
1904 quad1->g = models[c]->palette[models[c]->data[index]][1];
1905 quad1->b = models[c]->palette[models[c]->data[index]][2];
1906
1907 node_t* newNode = list_AddNodeLast(&quads);
1908 newNode->element = quad1;
1909 newNode->deconstructor = &defaultDeconstructor;
1910 newNode->size = sizeof(polyquad_t);
1911 }
1912 }
1913 }
1914 oldcolor = newcolor;
1915 }
1916 if ( buildingquad == true )
1917 {
1918 // add the last two vertices to the previous quad
1919 buildingquad = false;
1920
1921 node_t* currentNode = quads.last;
1922 quad1 = (polyquad_t*) currentNode->element;
1923 quad1->vertex[1].x = x - model->sizex / 2.f;
1924 quad1->vertex[1].y = y - model->sizey / 2.f + 1;
1925 quad1->vertex[1].z = z - model->sizez / 2.f - 1;
1926 quad1->vertex[2].x = x - model->sizex / 2.f;
1927 quad1->vertex[2].y = y - model->sizey / 2.f;
1928 quad1->vertex[2].z = z - model->sizez / 2.f - 1;
1929
1930 // optimize quad
1931 node_t* node;
1932 for ( i = 0, node = quads.first; i < numquads - 1; i++, node = node->next )
1933 {
1934 quad2 = (polyquad_t*)node->element;
1935 if ( quad1->side == quad2->side )
1936 {
1937 if ( quad1->r == quad2->r && quad1->g == quad2->g && quad1->b == quad2->b )
1938 {
1939 if ( quad2->vertex[0].x == quad1->vertex[3].x && quad2->vertex[0].y == quad1->vertex[3].y && quad2->vertex[0].z == quad1->vertex[3].z )
1940 {
1941 if ( quad2->vertex[1].x == quad1->vertex[2].x && quad2->vertex[1].y == quad1->vertex[2].y && quad2->vertex[1].z == quad1->vertex[2].z )
1942 {
1943 quad2->vertex[0].y++;
1944 quad2->vertex[1].y++;
1945 list_RemoveNode(currentNode);
1946 numquads--;
1947 polymodels[c].numfaces -= 2;
1948 break;
1949 }
1950 }
1951 }
1952 }
1953 }
1954 }
1955 }
1956 }
1957
1958 // translate quads into triangles
1959 polymodels[c].faces = (polytriangle_t*) malloc(sizeof(polytriangle_t) * polymodels[c].numfaces);
1960 for ( i = 0; i < polymodels[c].numfaces; i++ )
1961 {
1962 node_t* node = list_Node(&quads, i / 2);
1963 polyquad_t* quad = (polyquad_t*)node->element;
1964 polymodels[c].faces[i].r = quad->r;
1965 polymodels[c].faces[i].g = quad->g;
1966 polymodels[c].faces[i].b = quad->b;
1967 if ( i % 2 )
1968 {
1969 polymodels[c].faces[i].vertex[0] = quad->vertex[0];
1970 polymodels[c].faces[i].vertex[1] = quad->vertex[1];
1971 polymodels[c].faces[i].vertex[2] = quad->vertex[2];
1972 }
1973 else
1974 {
1975 polymodels[c].faces[i].vertex[0] = quad->vertex[0];
1976 polymodels[c].faces[i].vertex[1] = quad->vertex[2];
1977 polymodels[c].faces[i].vertex[2] = quad->vertex[3];
1978 }
1979 }
1980
1981 // free up quads for the next model
1982 list_FreeAll(&quads);
1983 }
1984 if (useModelCache && (model_cache = openDataFile("models.cache", "wb")))
1985 {
1986 char modelCacheHeader[32] = "BARONY";
1987 strcat(modelCacheHeader, VERSION);
1988 fwrite(&modelCacheHeader, sizeof(char), strlen(modelCacheHeader), model_cache);
1989 for (size_t model_index = 0; model_index < nummodels; model_index++)
1990 {
1991 polymodel_t *cur = &polymodels[model_index];
1992 fwrite(&cur->numfaces, sizeof(cur->numfaces), 1, model_cache);
1993 fwrite(cur->faces, sizeof(polytriangle_t), cur->numfaces, model_cache);
1994 }
1995 fclose(model_cache);
1996 }
1997
1998 // now store models into VBOs
1999 if ( !disablevbos )
2000 {
2001 generateVBOs(start, end);
2002 }
2003 }
2004
2005 /*-------------------------------------------------------------------------------
2006
2007 generateVBOs
2008
2009 generates VBOs/VAs from polymodel data
2010
2011 -------------------------------------------------------------------------------*/
2012
generateVBOs(int start,int end)2013 void generateVBOs(int start, int end)
2014 {
2015 int count = end - start;
2016
2017 std::unique_ptr<GLuint[]> vas(new GLuint[count]);
2018 SDL_glGenVertexArrays(count, vas.get());
2019
2020 std::unique_ptr<GLuint[]> vbos(new GLuint[count]);
2021 SDL_glGenBuffers(count, vbos.get());
2022
2023 std::unique_ptr<GLuint[]> color_buffers(new GLuint[count]);
2024 SDL_glGenBuffers(count, color_buffers.get());
2025
2026 std::unique_ptr<GLuint[]> color_shifted_buffers(new GLuint[count]);
2027 SDL_glGenBuffers(count, color_shifted_buffers.get());
2028
2029 for ( int c = start; c < end; ++c )
2030 {
2031 polymodel_t *model = &polymodels[c];
2032 std::unique_ptr<GLfloat[]> points(new GLfloat[9 * model->numfaces]);
2033 std::unique_ptr<GLfloat[]> colors(new GLfloat[9 * model->numfaces]);
2034 std::unique_ptr<GLfloat[]> colors_shifted(new GLfloat[9 * model->numfaces]);
2035 for ( int i = 0; i < model->numfaces; i++ )
2036 {
2037 const polytriangle_t *face = &model->faces[i];
2038 for (int vert_index = 0; vert_index < 3; vert_index++)
2039 {
2040 int data_index = i * 9 + vert_index * 3;
2041 const vertex_t *vert = &face->vertex[vert_index];
2042
2043 points[data_index] = vert->x;
2044 points[data_index + 1] = -vert->z;
2045 points[data_index + 2] = vert->y;
2046
2047 colors[data_index] = face->r / 255.f;
2048 colors[data_index + 1] = face->g / 255.f;
2049 colors[data_index + 2] = face->b / 255.f;
2050
2051 colors_shifted[data_index] = face->b / 255.f;
2052 colors_shifted[data_index + 1] = face->r / 255.f;
2053 colors_shifted[data_index + 2] = face->g / 255.f;
2054 }
2055 }
2056 model->va = vas[c - start];
2057 model->vbo = vbos[c - start];
2058 model->colors = color_buffers[c - start];
2059 model->colors_shifted = color_shifted_buffers[c - start];
2060 SDL_glBindVertexArray(model->va);
2061
2062 // vertex data
2063 // Well, the generic vertex array are not used, so disabled (making it run on any OpenGL 1.5 hardware)
2064 SDL_glBindBuffer(GL_ARRAY_BUFFER, model->vbo);
2065 SDL_glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 9 * model->numfaces, points.get(), GL_STATIC_DRAW);
2066
2067 // color data
2068 SDL_glBindBuffer(GL_ARRAY_BUFFER, model->colors);
2069 SDL_glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 9 * model->numfaces, colors.get(), GL_STATIC_DRAW); // Set the size and data of our VBO and set it to STATIC_DRAW
2070
2071 // shifted color data
2072 SDL_glBindBuffer(GL_ARRAY_BUFFER, model->colors_shifted);
2073 SDL_glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 9 * model->numfaces, colors_shifted.get(), GL_STATIC_DRAW); // Set the size and data of our VBO and set it to STATIC_DRAW
2074 }
2075 }
2076
2077 /*-------------------------------------------------------------------------------
2078
2079 deinitApp
2080
2081 frees all memory consumed by the application and terminates the engine
2082
2083 -------------------------------------------------------------------------------*/
deinitApp()2084 int deinitApp()
2085 {
2086 Uint32 c;
2087 #ifdef USE_OPENAL
2088 closeOPENAL();
2089 #endif
2090 // close engine
2091 printlog("closing engine...\n");
2092 printlog("removing engine timer...\n");
2093 if ( timer )
2094 {
2095 SDL_RemoveTimer(timer);
2096 }
2097 printlog("freeing engine resources...\n");
2098 list_FreeAll(&button_l);
2099 list_FreeAll(&entitiesdeleted);
2100 if ( fancyWindow_bmp )
2101 {
2102 SDL_FreeSurface(fancyWindow_bmp);
2103 }
2104 if ( font8x8_bmp )
2105 {
2106 SDL_FreeSurface(font8x8_bmp);
2107 }
2108 if ( font12x12_bmp )
2109 {
2110 SDL_FreeSurface(font12x12_bmp);
2111 }
2112 if ( font16x16_bmp )
2113 {
2114 SDL_FreeSurface(font16x16_bmp);
2115 }
2116 if ( ttf8 )
2117 {
2118 TTF_CloseFont(ttf8);
2119 }
2120 if ( ttf12 )
2121 {
2122 TTF_CloseFont(ttf12);
2123 }
2124 if ( ttf16 )
2125 {
2126 TTF_CloseFont(ttf16);
2127 }
2128
2129 printlog("freeing map data...\n");
2130 if ( map.entities != NULL )
2131 {
2132 list_FreeAll(map.entities);
2133 free(map.entities);
2134 }
2135 if ( map.creatures != nullptr)
2136 {
2137 list_FreeAll(map.creatures); //TODO: Need to call this? Entities are only pointed to by the thing, not owned.
2138 delete map.creatures;
2139 }
2140 list_FreeAll(&light_l);
2141 if ( map.tiles != NULL )
2142 {
2143 free(map.tiles);
2144 }
2145 if ( lightmap != NULL )
2146 {
2147 free(lightmap);
2148 }
2149 if ( lightmapSmoothed )
2150 {
2151 free(lightmapSmoothed);
2152 }
2153 if ( vismap != NULL )
2154 {
2155 free(vismap);
2156 }
2157
2158 for ( c = 0; c < HASH_SIZE; c++ )
2159 {
2160 list_FreeAll(&ttfTextHash[c]);
2161 }
2162
2163 // free textures
2164 printlog("freeing textures...\n");
2165 if ( tiles != NULL )
2166 {
2167 for ( c = 0; c < numtiles; c++ )
2168 {
2169 if ( tiles[c] )
2170 {
2171 SDL_FreeSurface(tiles[c]);
2172 }
2173 }
2174 free(tiles);
2175 }
2176 if ( animatedtiles )
2177 {
2178 free(animatedtiles);
2179 animatedtiles = nullptr;
2180 }
2181 if ( lavatiles )
2182 {
2183 free(lavatiles);
2184 lavatiles = nullptr;
2185 }
2186 if ( swimmingtiles )
2187 {
2188 free(swimmingtiles);
2189 swimmingtiles = nullptr;
2190 }
2191
2192 // free sprites
2193 printlog("freeing sprites...\n");
2194 if ( sprites != NULL )
2195 {
2196 for ( c = 0; c < numsprites; c++ )
2197 {
2198 if ( sprites[c] )
2199 {
2200 SDL_FreeSurface(sprites[c]);
2201 }
2202 }
2203 free(sprites);
2204 }
2205
2206 // free achievement images
2207 for (auto& item : achievementImages)
2208 {
2209 SDL_FreeSurface(item.second);
2210 }
2211 achievementImages.clear();
2212
2213 // free models
2214 printlog("freeing models...\n");
2215 if ( models != NULL )
2216 {
2217 for ( c = 0; c < nummodels; c++ )
2218 {
2219 if ( models[c] != NULL )
2220 {
2221 if ( models[c]->data )
2222 {
2223 free(models[c]->data);
2224 }
2225 free(models[c]);
2226 }
2227 }
2228 free(models);
2229 }
2230 if ( polymodels != NULL )
2231 {
2232 for ( c = 0; c < nummodels; c++ )
2233 {
2234 if ( polymodels[c].faces )
2235 {
2236 free(polymodels[c].faces);
2237 }
2238 }
2239 if ( !disablevbos )
2240 {
2241 for ( c = 0; c < nummodels; c++ )
2242 {
2243 if ( polymodels[c].vbo )
2244 {
2245 SDL_glDeleteBuffers(1, &polymodels[c].vbo);
2246 }
2247 if ( polymodels[c].colors )
2248 {
2249 SDL_glDeleteBuffers(1, &polymodels[c].colors);
2250 }
2251 if ( polymodels[c].va )
2252 {
2253 SDL_glDeleteVertexArrays(1, &polymodels[c].va);
2254 }
2255 }
2256 }
2257 free(polymodels);
2258 }
2259
2260 // free sounds
2261 #ifdef USE_FMOD
2262 printlog("freeing sounds...\n");
2263 if ( sounds != NULL )
2264 {
2265 for ( c = 0; c < numsounds && !no_sound; c++ )
2266 {
2267 if (sounds[c] != NULL)
2268 {
2269 if (sounds[c] != NULL)
2270 {
2271 FMOD_Sound_Release(sounds[c]); //Free the sound's FMOD sound.
2272 }
2273 //free(sounds[c]); //Then free the sound itself.
2274 }
2275 }
2276 free(sounds); //Then free the sound array.
2277 }
2278 #endif
2279
2280 // delete opengl buffers
2281 if ( allsurfaces != NULL )
2282 {
2283 free(allsurfaces);
2284 }
2285 if ( texid != NULL )
2286 {
2287 glDeleteTextures(MAXTEXTURES, texid);
2288 free(texid);
2289 }
2290
2291 // delete opengl buffers
2292 /*SDL_glDeleteBuffers(MAXBUFFERS,vboid);
2293 if( vboid != NULL )
2294 free(vboid);
2295 SDL_glDeleteVertexArrays(MAXBUFFERS,vaoid);
2296 if( vaoid != NULL )
2297 free(vaoid);*/
2298
2299 // close network interfaces
2300 closeNetworkInterfaces();
2301
2302 // shutdown SDL subsystems
2303 printlog("shutting down SDL and its subsystems...\n");
2304 SDLNet_Quit();
2305 IMG_Quit();
2306 //Mix_HaltChannel(-1);
2307 //Mix_CloseAudio();
2308 #ifdef USE_FMOD
2309 if ( fmod_system )
2310 {
2311 FMOD_System_Close(fmod_system);
2312 FMOD_System_Release(fmod_system);
2313 fmod_system = NULL;
2314 }
2315 #endif
2316 if ( screen )
2317 {
2318 SDL_DestroyWindow(screen);
2319 screen = NULL;
2320 }
2321 if ( renderer )
2322 {
2323 #ifdef APPLE
2324 SDL_DestroyRenderer(renderer);
2325 #else
2326 SDL_GL_DeleteContext(renderer);
2327 #endif
2328 renderer = NULL;
2329 }
2330 if ( mainsurface )
2331 {
2332 SDL_FreeSurface(mainsurface);
2333 mainsurface = NULL;
2334 }
2335 TTF_Quit();
2336 SDL_Quit();
2337
2338 // free video and input buffers
2339 if ( zbuffer != NULL )
2340 {
2341 free(zbuffer);
2342 }
2343 if ( clickmap != NULL )
2344 {
2345 free(clickmap);
2346 }
2347
2348 // shutdown steamworks
2349 #ifdef STEAMWORKS
2350 if ( steam_init )
2351 {
2352 printlog("storing user stats to Steam...\n");
2353 SteamUserStats()->StoreStats();
2354 if ( g_SteamLeaderboards )
2355 {
2356 delete g_SteamLeaderboards;
2357 }
2358 if ( g_SteamWorkshop )
2359 {
2360 delete g_SteamWorkshop;
2361 }
2362 if ( g_SteamStatistics )
2363 {
2364 delete g_SteamStatistics;
2365 }
2366 SteamAPI_Shutdown();
2367 }
2368 #endif
2369
2370
2371 int numLogFilesToKeepInArchive = 30;
2372 // archive logfiles.
2373 char lognamewithTimestamp[128];
2374 std::time_t timeNow = std::time(nullptr);
2375 struct tm *localTimeNow = nullptr;
2376 localTimeNow = std::localtime(&timeNow);
2377
2378 snprintf(lognamewithTimestamp, 127, "log_%4d%02d%02d_%02d%02d%02d.txt",
2379 localTimeNow->tm_year + 1900, localTimeNow->tm_mon + 1, localTimeNow->tm_mday, localTimeNow->tm_hour, localTimeNow->tm_min, localTimeNow->tm_sec);
2380
2381 std::string logarchivePath = outputdir;
2382 logarchivePath.append(PHYSFS_getDirSeparator()).append("logfiles").append(PHYSFS_getDirSeparator());
2383 std::string logarchiveFilePath = logarchivePath + lognamewithTimestamp;
2384
2385
2386 // prune any old logfiles if qty >= numLogFilesToKeepInArchive
2387 std::vector<std::pair<int, std::string>> sortedLogFiles;
2388 auto archivedFiles = directoryContents(logarchivePath.c_str(), false, true);
2389 if ( !archivedFiles.empty() && archivedFiles.size() >= numLogFilesToKeepInArchive )
2390 {
2391 // first find the date modified of log files.
2392 for ( auto file : archivedFiles )
2393 {
2394 struct tm *tm = nullptr;
2395 //#ifdef WINDOWS
2396 std::string filePath = logarchivePath + file;
2397 #ifdef WINDOWS
2398 struct _stat fileDateModified;
2399 if ( _stat(filePath.c_str(), &fileDateModified) == 0 )
2400 #else
2401 struct stat fileDateModified;
2402 if ( stat(filePath.c_str(), &fileDateModified) == 0 )
2403 #endif
2404 {
2405 tm = localtime(&fileDateModified.st_mtime);
2406 }
2407 //#else
2408 // UNIX/MAC
2409 /*struct stat fileDateModified;
2410 if ( stat(filePath.c_str(), &fileDateModified) == 0 )
2411 {
2412 tm = localtime(&fileDateModified.st_mtime);
2413 }*/
2414 //#endif
2415 if ( tm )
2416 {
2417 int timeDifference = std::difftime(timeNow, mktime(tm));
2418 sortedLogFiles.push_back(std::make_pair(timeDifference, file));
2419 }
2420 }
2421 }
2422 std::sort(sortedLogFiles.begin(), sortedLogFiles.end()); // sort most recent to oldest.
2423 while ( sortedLogFiles.size() >= numLogFilesToKeepInArchive )
2424 {
2425 std::string logToRemove = logarchivePath + sortedLogFiles.back().second;
2426 printlog("notice: Deleting archived log file %s due to number of old log files (%d) exceeds limit of %d.", logToRemove.c_str(), sortedLogFiles.size(), numLogFilesToKeepInArchive);
2427 if ( access(logToRemove.c_str(), F_OK) != -1 )
2428 {
2429 int result = remove(logToRemove.c_str());
2430 if ( result )
2431 {
2432 printlog("warning: failed to delete logfile %s", logToRemove.c_str());
2433 }
2434 }
2435 else
2436 {
2437 printlog("warning: could not access logfile %s", logToRemove.c_str());
2438 }
2439 sortedLogFiles.pop_back();
2440 }
2441
2442 if ( PHYSFS_isInit() )
2443 {
2444 PHYSFS_deinit();
2445 printlog("[PhysFS]: De-initializing...\n");
2446 }
2447
2448 // free currently loaded language if any
2449 freeLanguages();
2450 printlog("notice: archiving log file as %s...\n", logarchiveFilePath.c_str());
2451 printlog("success\n");
2452 fclose(logfile);
2453
2454 // copy the log file into the archives.
2455 char logToArchive[PATH_MAX];
2456 completePath(logToArchive, "log.txt", outputdir);
2457 #ifdef WINDOWS
2458 CopyFileA(logToArchive, logarchiveFilePath.c_str(), false);
2459 #else //LINUX & APPLE
2460 std::stringstream ss;
2461 ss << "cp " << logToArchive << " " << logarchiveFilePath.c_str();
2462 system(ss.str().c_str());
2463 #endif // WINDOWS
2464 return 0;
2465 }
2466
2467 #ifdef PANDORA
GO_InitFBO()2468 void GO_InitFBO()
2469 {
2470 glBindFramebuffer(GL_FRAMEBUFFER, 0);
2471 if(fbo_fbo) {
2472 glDeleteFramebuffers(1, &fbo_fbo); fbo_fbo = 0;
2473 glDeleteRenderbuffers(1, &fbo_ren); fbo_ren = 0;
2474 if(fbo_trn) {
2475 glDeleteRenderbuffers(1, &fbo_trn); fbo_trn = 0;
2476 }
2477 if(fbo_tex) {
2478 glDeleteTextures(1, &fbo_tex); fbo_tex = 0;
2479 }
2480 }
2481
2482 // Pandora, create the FBO!
2483 bool small_fbo=((xres==800) && (yres==480));
2484 glGenFramebuffers(1, &fbo_fbo);
2485 glBindFramebuffer(GL_FRAMEBUFFER, fbo_fbo);
2486 if(small_fbo) {
2487 glGenRenderbuffers(1, &fbo_trn);
2488 glBindRenderbuffer(GL_RENDERBUFFER, fbo_trn);
2489 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 1024, 512);
2490 glBindRenderbuffer(GL_RENDERBUFFER, 0);
2491 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fbo_trn);
2492 } else {
2493 glGenTextures(1, &fbo_tex);
2494 glBindTexture(GL_TEXTURE_2D, fbo_tex);
2495 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
2496 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2497 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2498 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2499 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
2500 glBindTexture(GL_TEXTURE_2D, 0);
2501 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo_tex, 0);
2502 }
2503 glGenRenderbuffers(1, &fbo_ren);
2504 glBindRenderbuffer(GL_RENDERBUFFER, fbo_ren);
2505 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, 1024, (small_fbo)?512:1024);
2506 glBindRenderbuffer(GL_RENDERBUFFER, 0);
2507 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fbo_ren);
2508 glBindFramebuffer(GL_FRAMEBUFFER, 0);
2509 if(!small_fbo)
2510 glBindFramebuffer(GL_FRAMEBUFFER, fbo_fbo);
2511
2512 }
2513 #endif
2514
2515 /*-------------------------------------------------------------------------------
2516
2517 initVideo
2518
2519 Sets the SDL/openGL context using global video variables
2520
2521 -------------------------------------------------------------------------------*/
2522
initVideo()2523 bool initVideo()
2524 {
2525 SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 1/*3*/ ); //Why GL 3.0? using only fixed pipeline stuff here
2526 SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 0 );
2527 SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );
2528 SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
2529 SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 24 );
2530 //SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE );
2531 //SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, 1 );
2532 //SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, 4 );
2533
2534 printlog("setting display mode to %dx%d...\n", xres, yres);
2535 Uint32 flags = 0;
2536 #ifdef PANDORA
2537 fullscreen = true;
2538 #endif
2539 if ( fullscreen )
2540 {
2541 flags |= SDL_WINDOW_FULLSCREEN;
2542 }
2543 if ( borderless )
2544 {
2545 flags |= SDL_WINDOW_BORDERLESS;
2546 }
2547 if ( !game )
2548 {
2549 flags |= SDL_WINDOW_RESIZABLE;
2550 }
2551 if ( !softwaremode )
2552 {
2553 flags |= SDL_WINDOW_OPENGL;
2554 }
2555 #ifdef APPLE
2556 if ( fullscreen )
2557 {
2558 flags |= SDL_WINDOW_BORDERLESS;
2559 }
2560 SDL_DestroyWindow(screen);
2561 screen = NULL;
2562 #endif
2563 #ifdef PANDORA
2564 int screen_width = 800;
2565 #else
2566 int screen_width = xres;
2567 #endif
2568 if ( !screen )
2569 {
2570 #ifdef PANDORA
2571 if ((screen = SDL_CreateWindow( window_title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, screen_width, 480, flags )) == NULL)
2572 #else
2573 if ((screen = SDL_CreateWindow( window_title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, screen_width, yres, flags )) == NULL)
2574 #endif
2575 {
2576 printlog("failed to set video mode.\n");
2577 return false;
2578 }
2579 }
2580 else
2581 {
2582 #ifdef PANDORA
2583 SDL_SetWindowSize(screen, screen_width, 480);
2584 #else
2585 SDL_SetWindowSize(screen, screen_width, yres);
2586 #endif
2587 if ( fullscreen )
2588 {
2589 SDL_SetWindowFullscreen(screen, SDL_WINDOW_FULLSCREEN);
2590 }
2591 else
2592 {
2593 SDL_SetWindowFullscreen(screen, 0);
2594 }
2595 if ( borderless )
2596 {
2597 SDL_SetWindowBordered(screen, SDL_bool::SDL_FALSE);
2598 }
2599 else
2600 {
2601 SDL_SetWindowBordered(screen, SDL_bool::SDL_TRUE);
2602 }
2603 SDL_SetWindowPosition(screen, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
2604 }
2605 if ( !renderer )
2606 {
2607 #ifdef APPLE
2608 if ((renderer = SDL_CreateRenderer(screen, -1, 0)) == NULL)
2609 {
2610 #else
2611 if ((renderer = SDL_GL_CreateContext(screen)) == NULL)
2612 {
2613 #endif
2614 printlog("failed to create SDL renderer. Reason: \"%s\"\n", SDL_GetError());
2615 printlog("You may need to update your video drivers.\n");
2616 return false;
2617 }
2618 }
2619 #ifndef APPLE
2620 SDL_GL_MakeCurrent(screen, renderer);
2621 #endif
2622 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
2623 Uint32 rmask = 0xff000000;
2624 Uint32 gmask = 0x00ff0000;
2625 Uint32 bmask = 0x0000ff00;
2626 Uint32 amask = 0x000000ff;
2627 #else
2628 Uint32 rmask = 0x000000ff;
2629 Uint32 gmask = 0x0000ff00;
2630 Uint32 bmask = 0x00ff0000;
2631 Uint32 amask = 0xff000000;
2632 #endif
2633 if ((mainsurface = SDL_CreateRGBSurface(0, xres, yres, 32, rmask, gmask, bmask, amask)) == NULL)
2634 {
2635 printlog("failed to create main window surface.\n");
2636 return false;
2637 }
2638 if ( !softwaremode )
2639 {
2640 #ifdef PANDORA
2641 GO_InitFBO();
2642 #endif
2643 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
2644 glEnable(GL_TEXTURE_2D);
2645 glEnable(GL_CULL_FACE);
2646 glCullFace(GL_BACK);
2647 glEnable(GL_BLEND);
2648 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2649 //glEnableClientState(GL_VERTEX_ARRAY);
2650 glMatrixMode( GL_MODELVIEW );
2651 glLoadIdentity();
2652 glMatrixMode( GL_PROJECTION );
2653 glLoadIdentity();
2654 glClearColor( 0, 0, 0, 0 );
2655 }
2656
2657 if ( verticalSync )
2658 {
2659 SDL_GL_SetSwapInterval(1);
2660 }
2661 else
2662 {
2663 SDL_GL_SetSwapInterval(0);
2664 }
2665 if ( SDL_SetWindowBrightness(screen, vidgamma) < 0 )
2666 {
2667 printlog("warning: failed to change gamma setting:\n%s\n", SDL_GetError());
2668 return true;
2669 }
2670 printlog("display changed successfully.\n");
2671 return true;
2672 }
2673
2674 /*-------------------------------------------------------------------------------
2675
2676 changeVideoMode
2677
2678 In windows: saves the openGL context, sets the video mode, and restores
2679 the context
2680 otherwise: acts as a wrapper for initVideo
2681
2682 -------------------------------------------------------------------------------*/
2683
2684 bool changeVideoMode()
2685 {
2686 printlog("changing video mode.\n");
2687 #ifdef PANDORA
2688 GO_InitFBO();
2689 #else
2690 int c;
2691
2692 // delete old texture names (they're going away anyway)
2693 glDeleteTextures(MAXTEXTURES, texid);
2694
2695 // delete vertex data
2696 if ( !disablevbos )
2697 {
2698 for ( c = 0; c < nummodels; c++ )
2699 {
2700 SDL_glDeleteBuffers(1, &polymodels[c].vbo);
2701 SDL_glDeleteBuffers(1, &polymodels[c].colors);
2702 SDL_glDeleteVertexArrays(1, &polymodels[c].va);
2703 }
2704 }
2705
2706 /*if( screen ) {
2707 SDL_DestroyWindow(screen);
2708 screen = NULL;
2709 }*/
2710 if ( renderer )
2711 {
2712 #ifdef APPLE
2713 SDL_DestroyRenderer(renderer);
2714 #else
2715 SDL_GL_DeleteContext(renderer);
2716 #endif
2717 renderer = NULL;
2718 }
2719 if ( mainsurface )
2720 {
2721 SDL_FreeSurface(mainsurface);
2722 mainsurface = NULL;
2723 }
2724
2725 // set video mode
2726 int result = initVideo();
2727 if ( !result )
2728 {
2729 xres = 960;
2730 yres = 600;
2731 fullscreen = 0;
2732 borderless = false;
2733 printlog("defaulting to safe video mode...\n");
2734 if ( !initVideo() )
2735 {
2736 return false;
2737 }
2738 }
2739
2740 // now reload all textures
2741 glGenTextures(MAXTEXTURES, texid);
2742 for ( c = 1; c < imgref; c++ )
2743 {
2744 glLoadTexture(allsurfaces[c], c);
2745 }
2746
2747 // regenerate vbos
2748 if ( !disablevbos )
2749 {
2750 generateVBOs(0, nummodels);
2751 }
2752 #endif
2753 // success
2754 return true;
2755 }
2756
2757 /*-------------------------------------------------------------------------------
2758
2759 loadItemLists()
2760
2761 loads the global item whitelist/blacklists and level curve.
2762
2763 -------------------------------------------------------------------------------*/
2764
2765 bool loadItemLists()
2766 {
2767 //FILE* fp;
2768 int c;
2769
2770 // open log file
2771 if ( !logfile )
2772 {
2773 openLogFile();
2774 }
2775
2776 // compose filename
2777 //char filename[128] = "items/items_global.txt";
2778 std::string itemsTxtDirectory = PHYSFS_getRealDir("items/items_global.txt");
2779 itemsTxtDirectory.append(PHYSFS_getDirSeparator()).append("items/items_global.txt");
2780 // check if item list is valid
2781 if ( !dataPathExists(itemsTxtDirectory.c_str()) )
2782 {
2783 // file doesn't exist
2784 printlog("error: unable to locate global item list file: '%s'", itemsTxtDirectory.c_str());
2785 return false;
2786 }
2787
2788 std::vector<std::string> itemLevels = getLinesFromDataFile(itemsTxtDirectory);
2789 std::string line;
2790 int itemIndex = 0;
2791
2792 for ( std::vector<std::string>::const_iterator i = itemLevels.begin(); i != itemLevels.end(); ++i ) {
2793 // process i
2794 line = *i;
2795 if ( line[0] == '#' || line[0] == '\n' )
2796 {
2797 continue;
2798 }
2799 std::size_t found = line.find('#');
2800 if ( found != std::string::npos )
2801 {
2802 char tmp[128];
2803 std::string sub = line.substr(0, found);
2804 strncpy(tmp, sub.c_str(), sub.length());
2805 tmp[sub.length()] = '\0';
2806 //printlog("%s", tmp);
2807 items[itemIndex].level = atoi(tmp);
2808 ++itemIndex;
2809 }
2810 }
2811
2812 printlog("successfully loaded global item list '%s' \n", itemsTxtDirectory.c_str());
2813 /*for ( c = 0; c < NUMITEMS; ++c )
2814 {
2815 printlog("%s level: %d", items[c].name_identified, items[c].level);
2816 }*/
2817 return true;
2818 }
2819