0.34.11 import: change 2
[rofl0r-df-libgraphics.git] / g_src / enabler.cpp
blobe5c4f8704d25b1ad6684af164e02b42bc8632153
1 #ifdef __APPLE__
2 # include "osx_messagebox.h"
3 #elif defined(unix)
4 # include <gtk/gtk.h>
5 #endif
7 #include <cassert>
9 #include "platform.h"
10 #include "enabler.h"
11 #include "random.h"
12 #include "init.h"
13 #include "music_and_sound_g.h"
15 #ifdef unix
16 # include <locale.h>
17 #endif
19 using namespace std;
21 enablerst enabler;
24 // For the printGLError macro
25 int glerrorcount = 0;
27 // Set to 0 when the game wants to quit
28 static int loopvar = 1;
30 // Reports an error to the user, using a MessageBox and stderr.
31 void report_error(const char *error_preface, const char *error_message)
33 char *buf = NULL;
34 // +4 = +colon +space +newline +nul
35 buf = new char[strlen(error_preface) + strlen(error_message) + 4];
36 sprintf(buf, "%s: %s\n", error_preface, error_message);
37 MessageBox(NULL, buf, "Error", MB_OK);
38 fprintf(stderr, "%s", buf);
39 delete [] buf;
42 Either<texture_fullid,texture_ttfid> renderer::screen_to_texid(int x, int y) {
43 const int tile = x * gps.dimy + y;
44 const unsigned char *s = screen + tile*4;
46 struct texture_fullid ret;
47 int ch;
48 int bold;
49 int fg;
50 int bg;
52 // TTF text does not get the full treatment.
53 if (s[3] == GRAPHICSTYPE_TTF) {
54 texture_ttfid texpos = *((unsigned int *)s) & 0xffffff;
55 return Either<texture_fullid,texture_ttfid>(texpos);
56 } else if (s[3] == GRAPHICSTYPE_TTFCONT) {
57 // TTFCONT means this is a tile that does not have TTF anchored on it, but is covered by TTF.
58 // Since this may actually be stale information, we'll draw it as a blank space,
59 ch = 32;
60 fg = bg = bold = 0;
61 } else {
62 // Otherwise, it's a normal (graphical?) tile.
63 ch = s[0];
64 bold = (s[3] != 0) * 8;
65 fg = (s[1] + bold) % 16;
66 bg = s[2] % 16;
69 static bool use_graphics = init.display.flag.has_flag(INIT_DISPLAY_FLAG_USE_GRAPHICS);
71 if (use_graphics) {
72 const long texpos = screentexpos[tile];
73 const char addcolor = screentexpos_addcolor[tile];
74 const unsigned char grayscale = screentexpos_grayscale[tile];
75 const unsigned char cf = screentexpos_cf[tile];
76 const unsigned char cbr = screentexpos_cbr[tile];
78 if (texpos) {
79 ret.texpos = texpos;
80 if (grayscale) {
81 ret.r = enabler.ccolor[cf][0];
82 ret.g = enabler.ccolor[cf][1];
83 ret.b = enabler.ccolor[cf][2];
84 ret.br = enabler.ccolor[cbr][0];
85 ret.bg = enabler.ccolor[cbr][1];
86 ret.bb = enabler.ccolor[cbr][2];
87 } else if (addcolor) {
88 goto use_ch;
89 } else {
90 ret.r = ret.g = ret.b = 1;
91 ret.br = ret.bg = ret.bb = 0;
93 goto skip_ch;
97 ret.texpos = enabler.is_fullscreen() ?
98 init.font.large_font_texpos[ch] :
99 init.font.small_font_texpos[ch];
100 use_ch:
101 ret.r = enabler.ccolor[fg][0];
102 ret.g = enabler.ccolor[fg][1];
103 ret.b = enabler.ccolor[fg][2];
104 ret.br = enabler.ccolor[bg][0];
105 ret.bg = enabler.ccolor[bg][1];
106 ret.bb = enabler.ccolor[bg][2];
108 skip_ch:
110 return Either<texture_fullid,texture_ttfid>(ret);
114 #ifdef CURSES
115 # include "renderer_curses.cpp"
116 #endif
117 #include "renderer_2d.hpp"
118 #include "renderer_opengl.hpp"
121 enablerst::enablerst() {
122 fullscreen = false;
123 sync = NULL;
124 renderer = NULL;
125 calculated_fps = calculated_gfps = frame_sum = gframe_sum = frame_last = gframe_last = 0;
126 fps = 100; gfps = 20;
127 fps_per_gfps = fps / gfps;
128 last_tick = 0;
131 void renderer::display()
133 const int dimx = init.display.grid_x;
134 const int dimy = init.display.grid_y;
135 static bool use_graphics = init.display.flag.has_flag(INIT_DISPLAY_FLAG_USE_GRAPHICS);
136 if (gps.force_full_display_count) {
137 // Update the entire screen
138 update_all();
139 } else {
140 Uint32 *screenp = (Uint32*)screen, *oldp = (Uint32*)screen_old;
141 if (use_graphics) {
142 int off = 0;
143 for (int x2=0; x2 < dimx; x2++) {
144 for (int y2=0; y2 < dimy; y2++, ++off, ++screenp, ++oldp) {
145 // We don't use pointers for the non-screen arrays because we mostly fail at the
146 // *first* comparison, and having pointers for the others would exceed register
147 // count.
148 // Partial printing (and color-conversion): Big-ass if.
149 if (*screenp == *oldp &&
150 screentexpos[off] == screentexpos_old[off] &&
151 screentexpos_addcolor[off] == screentexpos_addcolor_old[off] &&
152 screentexpos_grayscale[off] == screentexpos_grayscale_old[off] &&
153 screentexpos_cf[off] == screentexpos_cf_old[off] &&
154 screentexpos_cbr[off] == screentexpos_cbr_old[off])
156 // Nothing's changed, this clause deliberately empty
157 } else {
158 update_tile(x2, y2);
162 } else {
163 for (int x2=0; x2 < dimx; ++x2) {
164 for (int y2=0; y2 < dimy; ++y2, ++screenp, ++oldp) {
165 if (*screenp != *oldp) {
166 update_tile(x2, y2);
172 if (gps.force_full_display_count > 0) gps.force_full_display_count--;
175 void renderer::cleanup_arrays() {
176 if (screen) delete[] screen;
177 if (screentexpos) delete[] screentexpos;
178 if (screentexpos_addcolor) delete[] screentexpos_addcolor;
179 if (screentexpos_grayscale) delete[] screentexpos_grayscale;
180 if (screentexpos_cf) delete[] screentexpos_cf;
181 if (screentexpos_cbr) delete[] screentexpos_cbr;
182 if (screen_old) delete[] screen_old;
183 if (screentexpos_old) delete[] screentexpos_old;
184 if (screentexpos_addcolor_old) delete[] screentexpos_addcolor_old;
185 if (screentexpos_grayscale_old) delete[] screentexpos_grayscale_old;
186 if (screentexpos_cf_old) delete[] screentexpos_cf_old;
187 if (screentexpos_cbr_old) delete[] screentexpos_cbr_old;
190 void renderer::gps_allocate(int x, int y) {
191 cleanup_arrays();
193 gps.screen = screen = new unsigned char[x*y*4];
194 memset(screen, 0, x*y*4);
195 gps.screentexpos = screentexpos = new long[x*y];
196 memset(screentexpos, 0, x*y*sizeof(long));
197 gps.screentexpos_addcolor = screentexpos_addcolor = new char[x*y];
198 memset(screentexpos_addcolor, 0, x*y);
199 gps.screentexpos_grayscale = screentexpos_grayscale = new unsigned char[x*y];
200 memset(screentexpos_grayscale, 0, x*y);
201 gps.screentexpos_cf = screentexpos_cf = new unsigned char[x*y];
202 memset(screentexpos_cf, 0, x*y);
203 gps.screentexpos_cbr = screentexpos_cbr = new unsigned char[x*y];
204 memset(screentexpos_cbr, 0, x*y);
206 screen_old = new unsigned char[x*y*4];
207 memset(screen_old, 0, x*y*4);
208 screentexpos_old = new long[x*y];
209 memset(screentexpos_old, 0, x*y*sizeof(long));
210 screentexpos_addcolor_old = new char[x*y];
211 memset(screentexpos_addcolor_old, 0, x*y);
212 screentexpos_grayscale_old = new unsigned char[x*y];
213 memset(screentexpos_grayscale_old, 0, x*y);
214 screentexpos_cf_old = new unsigned char[x*y];
215 memset(screentexpos_cf_old, 0, x*y);
216 screentexpos_cbr_old = new unsigned char[x*y];
217 memset(screentexpos_cbr_old, 0, x*y);
219 gps.resize(x,y);
222 void renderer::swap_arrays() {
223 screen = screen_old; screen_old = gps.screen; gps.screen = screen;
224 screentexpos = screentexpos_old; screentexpos_old = gps.screentexpos; gps.screentexpos = screentexpos;
225 screentexpos_addcolor = screentexpos_addcolor_old; screentexpos_addcolor_old = gps.screentexpos_addcolor; gps.screentexpos_addcolor = screentexpos_addcolor;
226 screentexpos_grayscale = screentexpos_grayscale_old; screentexpos_grayscale_old = gps.screentexpos_grayscale; gps.screentexpos_grayscale = screentexpos_grayscale;
227 screentexpos_cf = screentexpos_cf_old; screentexpos_cf_old = gps.screentexpos_cf; gps.screentexpos_cf = screentexpos_cf;
228 screentexpos_cbr = screentexpos_cbr_old; screentexpos_cbr_old = gps.screentexpos_cbr; gps.screentexpos_cbr = screentexpos_cbr;
230 gps.screen_limit = gps.screen + gps.dimx * gps.dimy * 4;
233 void enablerst::pause_async_loop() {
234 struct async_cmd cmd;
235 cmd.cmd = async_cmd::pause;
236 async_tobox.write(cmd);
237 async_wait();
240 // Wait until the previous command has been acknowledged, /or/
241 // async_loop has quit. Incidentally execute any requests in the
242 // meantime.
243 void enablerst::async_wait() {
244 if (loopvar == 0) return;
245 async_msg r;
246 bool reset_textures = false;
247 for (;;) {
248 async_frombox.read(r);
249 switch (r.msg) {
250 case async_msg::quit:
251 loopvar = 0;
252 return;
253 case async_msg::complete:
254 if (reset_textures) {
255 puts("Resetting textures");
256 textures.remove_uploaded_textures();
257 textures.upload_textures();
259 return;
260 case async_msg::set_fps:
261 set_fps(r.fps);
262 async_fromcomplete.write();
263 break;
264 case async_msg::set_gfps:
265 set_gfps(r.fps);
266 async_fromcomplete.write();
267 break;
268 case async_msg::push_resize:
269 override_grid_size(r.x, r.y);
270 async_fromcomplete.write();
271 break;
272 case async_msg::pop_resize:
273 release_grid_size();
274 async_fromcomplete.write();
275 break;
276 case async_msg::reset_textures:
277 reset_textures = true;
278 break;
279 default:
280 puts("EMERGENCY: Unknown case in async_wait");
281 abort();
286 void enablerst::async_loop() {
287 async_paused = false;
288 async_frames = 0;
289 int total_frames = 0;
290 int fps = 100; // Just a thread-local copy
291 for (;;) {
292 // cout << "FRAMES: " << frames << endl;
293 // Check for commands
294 async_cmd cmd;
295 bool have_cmd = true;
296 do {
297 if (async_paused || (async_frames == 0 && !(enabler.flag & ENABLERFLAG_MAXFPS)))
298 async_tobox.read(cmd);
299 else
300 have_cmd = async_tobox.try_read(cmd);
301 // Obey the command, would you kindly.
302 if (have_cmd) {
303 switch (cmd.cmd) {
304 case async_cmd::pause:
305 async_paused = true;
306 // puts("Paused");
307 async_frombox.write(async_msg(async_msg::complete));
308 break;
309 case async_cmd::start:
310 async_paused = false;
311 async_frames = 0;
312 // puts("UNpaused");
313 break;
314 case async_cmd::render:
315 if (flag & ENABLERFLAG_RENDER) {
316 total_frames++;
317 renderer->swap_arrays();
318 if (total_frames % 1800 == 0)
319 ttf_manager.gc();
320 render_things();
321 flag &= ~ENABLERFLAG_RENDER;
322 update_gfps();
324 async_frombox.write(async_msg(async_msg::complete));
325 break;
326 case async_cmd::inc:
327 async_frames += cmd.val;
328 if (async_frames > fps*3) async_frames = fps*3; // Just in case
329 break;
330 case async_cmd::set_fps:
331 fps = cmd.val;
332 break;
335 } while (have_cmd);
336 // Run the main-loop, maybe
337 if (!async_paused && (async_frames || (enabler.flag & ENABLERFLAG_MAXFPS))) {
338 if (mainloop()) {
339 async_frombox.write(async_msg(async_msg::quit));
340 return; // We're done.
342 simticks.lock();
343 simticks.val++;
344 simticks.unlock();
345 async_frames--;
346 if (async_frames < 0) async_frames = 0;
347 update_fps();
349 SDL_NumJoysticks(); // Hook for dfhack
353 void enablerst::do_frame() {
354 // Check how long it's been, exactly
355 const Uint32 now = SDL_GetTicks();
356 const Uint32 interval = CLAMP(now - last_tick, 0, 1000); // Anything above a second doesn't count
357 // cout << last_tick << " + " << interval << " = " << now << endl;
358 last_tick = now;
360 // Update outstanding-frame counts
361 outstanding_frames += interval * fps / 1000;
362 outstanding_gframes += interval * gfps / 1000;
363 if (outstanding_gframes > 3) {
364 outstanding_gframes = 3;
366 // cout << outstanding_frames << " " << outstanding_gframes << endl;
368 // Update the loop's tick-counter suitably
369 if (outstanding_frames >= 1) {
370 async_cmd cmd(async_cmd::inc);
371 cmd.val = outstanding_frames;
372 outstanding_frames -= cmd.val;
373 async_tobox.write(cmd);
376 // Store the current time, for things that are fine with approximations
377 enabler.clock = SDL_GetTicks();
379 // If it's time to render..
380 if (outstanding_gframes >= 1 &&
381 (!sync || glClientWaitSync(sync, 0, 0) == GL_ALREADY_SIGNALED)) {
382 // Get the async-loop to render_things
383 async_cmd cmd(async_cmd::render);
384 async_tobox.write(cmd);
385 async_wait();
386 // Then finish here
387 renderer->display();
388 renderer->render();
389 gputicks.lock();
390 gputicks.val++;
391 gputicks.unlock();
392 outstanding_gframes--;
395 // Sleep until the next gframe
396 if (outstanding_gframes < 1) {
397 float fragment = 1 - outstanding_gframes;
398 float milliseconds = fragment / gfps * 1000;
399 // cout << milliseconds << endl;
400 SDL_Delay(milliseconds);
404 void enablerst::eventLoop_SDL()
407 SDL_Event event;
408 const SDL_Surface *screen = SDL_GetVideoSurface();
409 Uint32 mouse_lastused = 0;
410 SDL_ShowCursor(SDL_DISABLE);
412 // Initialize the grid
413 renderer->resize(screen->w, screen->h);
415 while (loopvar) {
416 Uint32 now = SDL_GetTicks();
417 bool paused_loop = false;
419 // Check for zoom commands
420 zoom_commands zoom;
421 while (async_zoom.try_read(zoom)) {
422 if (overridden_grid_sizes.size())
423 continue; // No zooming in movies
424 if (!paused_loop) {
425 pause_async_loop();
426 paused_loop = true;
428 if (zoom == zoom_fullscreen)
429 renderer->set_fullscreen();
430 else
431 renderer->zoom(zoom);
434 // Check for SDL events
435 while (SDL_PollEvent(&event)) {
436 // Make sure mainloop isn't running while we're processing input
437 if (!paused_loop) {
438 pause_async_loop();
439 paused_loop = true;
441 // Handle SDL events
442 switch (event.type) {
443 case SDL_KEYDOWN:
444 // Disable mouse if it's been long enough
445 if (mouse_lastused + 5000 < now) {
446 if(init.input.flag.has_flag(INIT_INPUT_FLAG_MOUSE_PICTURE)) {
447 // hide the mouse picture
448 // enabler.set_tile(0, TEXTURE_MOUSE, enabler.mouse_x, enabler.mouse_y);
450 SDL_ShowCursor(SDL_DISABLE);
452 case SDL_KEYUP:
453 case SDL_QUIT:
454 enabler.add_input(event, now);
455 break;
456 case SDL_MOUSEBUTTONDOWN:
457 case SDL_MOUSEBUTTONUP:
458 if (!init.input.flag.has_flag(INIT_INPUT_FLAG_MOUSE_OFF)) {
459 int isdown = (event.type == SDL_MOUSEBUTTONDOWN);
460 if (event.button.button == SDL_BUTTON_LEFT) {
461 enabler.mouse_lbut = isdown;
462 enabler.mouse_lbut_down = isdown;
463 if (!isdown)
464 enabler.mouse_lbut_lift = 0;
465 } else if (event.button.button == SDL_BUTTON_RIGHT) {
466 enabler.mouse_rbut = isdown;
467 enabler.mouse_rbut_down = isdown;
468 if (!isdown)
469 enabler.mouse_rbut_lift = 0;
470 } else
471 enabler.add_input(event, now);
473 break;
474 case SDL_MOUSEMOTION:
475 // Deal with the mouse hiding bit
476 mouse_lastused = now;
477 if(init.input.flag.has_flag(INIT_INPUT_FLAG_MOUSE_PICTURE)) {
478 // turn on mouse picture
479 // enabler.set_tile(gps.tex_pos[TEXTURE_MOUSE], TEXTURE_MOUSE,enabler.mouse_x, enabler.mouse_y);
480 } else {
481 SDL_ShowCursor(SDL_ENABLE);
483 break;
484 case SDL_ACTIVEEVENT:
485 enabler.clear_input();
486 if (event.active.state & SDL_APPACTIVE) {
487 if (event.active.gain) {
488 enabler.flag|=ENABLERFLAG_RENDER;
489 gps.force_full_display_count++;
492 break;
493 case SDL_VIDEOEXPOSE:
494 gps.force_full_display_count++;
495 enabler.flag|=ENABLERFLAG_RENDER;
496 break;
497 case SDL_VIDEORESIZE:
498 if (is_fullscreen());
499 //errorlog << "Caught resize event in fullscreen??\n";
500 else {
501 //gamelog << "Resizing window to " << event.resize.w << "x" << event.resize.h << endl << flush;
502 renderer->resize(event.resize.w, event.resize.h);
504 break;
505 } // switch (event.type)
506 } //while have event
508 // Update mouse state
509 if (!init.input.flag.has_flag(INIT_INPUT_FLAG_MOUSE_OFF)) {
510 int mouse_x = -1, mouse_y = -1, mouse_state;
511 // Check whether the renderer considers this valid input or not, and write it to gps
512 if ((SDL_GetAppState() & SDL_APPMOUSEFOCUS) &&
513 renderer->get_mouse_coords(mouse_x, mouse_y)) {
514 mouse_state = 1;
515 } else {
516 mouse_state = 0;
518 if (mouse_x != gps.mouse_x || mouse_y != gps.mouse_y ||
519 mouse_state != enabler.tracking_on) {
520 // Pause rendering loop and update values
521 if (!paused_loop) {
522 pause_async_loop();
523 paused_loop = true;
525 enabler.tracking_on = mouse_state;
526 gps.mouse_x = mouse_x;
527 gps.mouse_y = mouse_y;
531 if (paused_loop)
532 unpause_async_loop();
534 do_frame();
535 #if !defined(NO_FMOD)
536 // Call FMOD::System.update(). Manages a bunch of sound stuff.
537 musicsound.update();
538 #endif
542 int enablerst::loop(string cmdline) {
543 command_line = cmdline;
545 // Initialize the tick counters
546 simticks.write(0);
547 gputicks.write(0);
549 // Call DF's initialization routine
550 if (!beginroutine())
551 exit(EXIT_FAILURE);
553 // Allocate a renderer
554 if (init.display.flag.has_flag(INIT_DISPLAY_FLAG_TEXT)) {
555 #ifdef CURSES
556 renderer = new renderer_curses();
557 #else
558 report_error("PRINT_MODE", "TEXT not supported on windows");
559 exit(EXIT_FAILURE);
560 #endif
561 } else if (init.display.flag.has_flag(INIT_DISPLAY_FLAG_2D)) {
562 renderer = new renderer_2d();
563 } else if (init.display.flag.has_flag(INIT_DISPLAY_FLAG_ACCUM_BUFFER)) {
564 renderer = new renderer_accum_buffer();
565 } else if (init.display.flag.has_flag(INIT_DISPLAY_FLAG_FRAME_BUFFER)) {
566 renderer = new renderer_framebuffer();
567 } else if (init.display.flag.has_flag(INIT_DISPLAY_FLAG_PARTIAL_PRINT)) {
568 if (init.display.partial_print_count)
569 renderer = new renderer_partial();
570 else
571 renderer = new renderer_once();
572 } else if (init.display.flag.has_flag(INIT_DISPLAY_FLAG_VBO)) {
573 renderer = new renderer_vbo();
574 } else {
575 renderer = new renderer_opengl();
578 // At this point we should have a window that is setup to render DF.
579 if (init.display.flag.has_flag(INIT_DISPLAY_FLAG_TEXT)) {
580 #ifdef CURSES
581 eventLoop_ncurses();
582 #endif
583 } else {
584 SDL_EnableUNICODE(1);
585 eventLoop_SDL();
588 endroutine();
590 // Clean up graphical resources
591 delete renderer;
594 void enablerst::override_grid_size(int x, int y) {
595 if (SDL_ThreadID() != renderer_threadid) {
596 // Ask the renderer to do it
597 async_msg m(async_msg::push_resize);
598 m.x = x; m.y = y;
599 async_frombox.write(m);
600 async_fromcomplete.read();
601 } else {
602 // We are the renderer; do it.
603 overridden_grid_sizes.push(make_pair(init.display.grid_x,init.display.grid_y));
604 renderer->grid_resize(x, y);
608 void enablerst::release_grid_size() {
609 if (SDL_ThreadID() != renderer_threadid) {
610 async_frombox.write(async_msg(async_msg::pop_resize));
611 async_fromcomplete.read();
612 } else {
613 if (!overridden_grid_sizes.size()) return;
614 // FIXME: Find out whatever is causing release to be called too rarely; right now
615 // we're overriding once per movie but apparently only releasing for the last one.
616 pair<int,int> sz;
617 while (overridden_grid_sizes.size()) {
618 sz = overridden_grid_sizes.top();
619 overridden_grid_sizes.pop();
621 zoom_display(zoom_resetgrid);
625 void enablerst::zoom_display(zoom_commands command) {
626 async_zoom.write(command);
629 int enablerst::calculate_fps() {
630 if (frame_timings.size() < 50)
631 return get_fps();
632 else
633 return calculated_fps;
635 int enablerst::calculate_gfps() {
636 if (gframe_timings.size() < 50)
637 return get_gfps();
638 else
639 return calculated_gfps;
642 void enablerst::do_update_fps(queue<int> &q, int &sum, int &last, int &calc) {
643 while (q.size() > 50 && sum > 10000) {
644 sum -= q.front();
645 q.pop();
647 const int now = SDL_GetTicks();
648 const int interval = now - last;
649 q.push(interval);
650 sum += interval;
651 last = now;
652 if (sum)
653 calc = q.size() * 1000 / sum;
656 void enablerst::clear_fps() {
657 while (frame_timings.size())
658 frame_timings.pop();
659 frame_sum = 0;
660 frame_last = SDL_GetTicks();
661 calculated_fps = get_fps();
664 void enablerst::update_fps() {
665 do_update_fps(frame_timings, frame_sum, frame_last, calculated_fps);
668 void enablerst::update_gfps() {
669 do_update_fps(gframe_timings, gframe_sum, gframe_last, calculated_gfps);
672 void enablerst::set_fps(int fps) {
673 if (SDL_ThreadID() != renderer_threadid) {
674 async_msg m(async_msg::set_fps);
675 m.fps = fps;
676 async_paused = true;
677 async_frombox.write(m);
678 async_fromcomplete.read();
679 } else {
680 if (fps == 0)
681 fps = 1048576;
682 this->fps = fps;
683 fps_per_gfps = fps / gfps;
684 struct async_cmd cmd;
685 cmd.cmd = async_cmd::set_fps;
686 cmd.val = fps;
687 async_tobox.write(cmd);
688 async_tobox.write(async_cmd(async_cmd::start));
692 void enablerst::set_gfps(int gfps) {
693 if (SDL_ThreadID() != renderer_threadid) {
694 async_msg m(async_msg::set_gfps);
695 m.fps = gfps;
696 async_frombox.write(m);
697 async_fromcomplete.read();
698 } else {
699 if (gfps == 0)
700 gfps = 50;
701 this->gfps = gfps;
702 fps_per_gfps = fps / gfps;
706 int call_loop(void *dummy) {
707 enabler.async_loop();
708 return 0;
711 int main (int argc, char* argv[]) {
712 #ifdef unix
713 setlocale(LC_ALL, "");
714 #endif
715 #if !defined(__APPLE__) && defined(unix)
716 bool gtk_ok = false;
717 if (getenv("DISPLAY"))
718 gtk_ok = gtk_init_check(&argc, &argv);
719 #endif
721 // Initialise minimal SDL subsystems.
722 int retval = SDL_Init(SDL_INIT_TIMER);
723 // Report failure?
724 if (retval != 0) {
725 report_error("SDL initialization failure", SDL_GetError());
726 return false;
728 enabler.renderer_threadid = SDL_ThreadID();
730 // Spawn simulation thread
731 SDL_CreateThread(call_loop, NULL);
733 init.begin(); // Load init.txt settings
735 #if !defined(__APPLE__) && defined(unix)
736 if (!gtk_ok && !init.display.flag.has_flag(INIT_DISPLAY_FLAG_TEXT)) {
737 puts("Display not found and PRINT_MODE not set to TEXT, aborting.");
738 exit(EXIT_FAILURE);
740 if (init.display.flag.has_flag(INIT_DISPLAY_FLAG_TEXT) &&
741 init.display.flag.has_flag(INIT_DISPLAY_FLAG_USE_GRAPHICS)) {
742 puts("Graphical tiles are not compatible with text output, sorry");
743 exit(EXIT_FAILURE);
745 #endif
747 // Initialize video, if we /use/ video
748 retval = SDL_InitSubSystem(init.display.flag.has_flag(INIT_DISPLAY_FLAG_TEXT) ? 0 : SDL_INIT_VIDEO);
749 if (retval != 0) {
750 report_error("SDL initialization failure", SDL_GetError());
751 return false;
754 #ifdef linux
755 if (!init.media.flag.has_flag(INIT_MEDIA_FLAG_SOUND_OFF)) {
756 // Initialize OpenAL
757 if (!musicsound.initsound()) {
758 puts("Initializing OpenAL failed, no sound will be played");
759 init.media.flag.add_flag(INIT_MEDIA_FLAG_SOUND_OFF);
762 #endif
764 #ifdef WIN32
765 // Attempt to get as good a timer as possible
766 int ms = 1;
767 while (timeBeginPeriod(ms) != TIMERR_NOERROR) ms++;
768 #endif
770 // Load keyboard map
771 keybinding_init();
772 enabler.load_keybindings("data/init/interface.txt");
774 string cmdLine;
775 for (int i = 1; i < argc; ++i) {
776 char *option = argv[i];
777 string opt=option;
778 if(opt.length()>=1)
780 //main removes quotes, unlike the winmain version, so it has to be rebuilt
781 if(opt[0]=='-')
783 cmdLine += opt;
784 cmdLine += " ";
786 else
788 cmdLine += "\"";
789 cmdLine += opt;
790 cmdLine += "\"";
791 cmdLine += " ";
795 int result = enabler.loop(cmdLine);
797 SDL_Quit();
799 #ifdef WIN32
800 timeEndPeriod(ms);
801 #endif
803 return result;
806 char get_slot_and_addbit_uchar(unsigned char &addbit,long &slot,long checkflag,long slotnum)
808 if(checkflag<0)return 0;
810 //FIND PROPER SLOT
811 slot=checkflag>>3;
812 if(slot>=slotnum)return 0;
814 //FIND PROPER BIT IN THAT SLOT
815 addbit=1<<(checkflag%8);
817 return 1;
820 void text_system_file_infost::initialize_info()
822 std::ifstream fseed(filename.c_str());
823 if(fseed.is_open())
825 string str;
827 while(std::getline(fseed,str))
829 if(str.length()>0)number++;
832 else
834 string str;
835 str="Error Initializing Text: ";
836 str+=filename;
837 errorlog_string(str);
839 fseed.close();
842 void text_system_file_infost::get_text(text_infost &text)
844 text.clean();
846 if(number==0)return;
848 std::ifstream fseed(filename.c_str());
849 if(fseed.is_open())
851 string str;
853 int num=trandom(number);
855 //SKIP AHEAD TO THE RIGHT SPOT
856 while(num>0)
858 std::getline(fseed,str);
859 num--;
862 //PROCESS THE STRING INTO TEXT ELEMENTS
863 if(std::getline(fseed,str))
865 int curpos;
866 string nextstr;
867 char doing_long=0;
869 text_info_elementst *newel;
870 long end=str.length();
872 while(end>0)
874 if(isspace(str[end-1]))end--;
875 else break;
878 str.resize(end);
880 for(curpos=0;curpos<end;curpos++)
882 //HANDLE TOKEN OR ENDING
883 //TWO FILE TOKENS IN A ROW MEANS LONG
884 //ONE MEANS STRING
885 if(str[curpos]==file_token || curpos==end-1)
887 if(str[curpos]!=file_token)nextstr+=str[curpos];
889 //HAVE SOMETHING == SAVE IT
890 if(!nextstr.empty())
892 if(doing_long)
894 newel=new text_info_element_longst(atoi(nextstr.c_str()));
895 text.element.push_back(newel);
896 doing_long=0;
898 else
900 newel=new text_info_element_stringst(nextstr);
901 text.element.push_back(newel);
904 nextstr.erase();
906 //STARTING A LONG
907 else
909 doing_long=1;
912 //JUST ADD IN ANYTHING ELSE
913 else
915 nextstr+=str[curpos];
920 fseed.close();
923 void curses_text_boxst::add_paragraph(const string &src,int32_t para_width)
925 stringvectst sp;
926 sp.add_string(src);
927 add_paragraph(sp,para_width);
930 void curses_text_boxst::add_paragraph(stringvectst &src,int32_t para_width)
932 bool skip_leading_spaces=false;
934 //ADD EACH OF THE STRINGS ON IN TURN
935 string curstr;
936 long strlength=0;
937 long s,pos;
938 for(s=0;s<src.str.size();s++)
940 //GRAB EACH WORD, AND SEE IF IT FITS, IF NOT START A NEW LINE
941 for(pos=0;pos<src.str[s]->dat.size();pos++)
943 if(skip_leading_spaces)
945 if(src.str[s]->dat[pos]==' ')continue;
946 else skip_leading_spaces=false;
949 //ADD TO WORD
950 curstr+=src.str[s]->dat[pos];
952 //IF TOO LONG, CUT BACK TO FIRST SPACE
953 if(curstr.length()>para_width)
955 long opos=pos;
957 long minus=0;
960 pos--;
961 minus++;
962 }while(src.str[s]->dat[pos]!=' '&&pos>0);
964 //IF WENT ALL THE WAY BACK, INTRODUCE A SPACE
965 if(minus==curstr.size())
967 src.str[s]->dat.insert(opos-1," ");
969 else
971 curstr.resize(curstr.size()-minus);
972 text.add_string(curstr);
973 skip_leading_spaces=true;
975 curstr.erase();
980 //FLUSH FINAL BIT
981 if(!curstr.empty())text.add_string(curstr);