1 //some of this stuff is based on public domain code from nehe or opengl books over the years
2 //additions and modifications Copyright (c) 2008, Tarn Adams
3 //All rights reserved. See game.cpp or license.txt for more information.
10 #include <SDL/SDL_thread.h>
12 # include <SDL_ttf/SDL_ttf.h>
13 # include <SDL_image/SDL_image.h>
15 # include <SDL/SDL_ttf.h>
16 # include <SDL/SDL_image.h>
47 #include "enabler_input.h"
73 #define BIT18 131072UL
74 #define BIT19 262144UL
75 #define BIT20 524288UL
76 #define BIT21 1048576UL
77 #define BIT22 2097152UL
78 #define BIT23 4194304UL
79 #define BIT24 8388608UL
80 #define BIT25 16777216UL
81 #define BIT26 33554432UL
82 #define BIT27 67108864UL
83 #define BIT28 134217728UL
84 #define BIT29 268435456UL
85 #define BIT30 536870912UL
86 #define BIT31 1073741824UL
87 #define BIT32 2147483648UL
91 #define GAME_TITLE_STRING "Dwarf Fortress"
93 char get_slot_and_addbit_uchar(unsigned char &addbit
,long &slot
,long checkflag
,long slotnum
);
104 svector
<pstringst
*> str
;
106 void add_string(const string
&st
)
108 pstringst
*newp
=new pstringst
;
113 long add_unique_string(const string
&st
)
116 for(i
=(long)str
.size()-1;i
>=0;i
--)
118 if(str
[i
]->dat
==st
)return i
;
121 return (long)str
.size()-1;
124 void add_string(const char *st
)
128 pstringst
*newp
=new pstringst
;
134 void insert_string(long k
,const string
&st
)
136 pstringst
*newp
=new pstringst
;
138 if(str
.size()>k
)str
.insert(k
,newp
);
139 else str
.push_back(newp
);
156 void read_file(file_compressorst
&filecomp
,long loadversion
)
159 filecomp
.read_file(dummy
);
165 str
[s
]=new pstringst
;
166 filecomp
.read_file(str
[s
]->dat
);
169 void write_file(file_compressorst
&filecomp
)
171 long dummy
=str
.size();
172 filecomp
.write_file(dummy
);
177 filecomp
.write_file(str
[s
]->dat
);
181 void copy_from(stringvectst
&src
)
185 str
.resize(src
.str
.size());
188 for(s
=(long)src
.str
.size()-1;s
>=0;s
--)
190 str
[s
]=new pstringst
;
191 str
[s
]->dat
=src
.str
[s
]->dat
;
195 bool has_string(const string
&st
)
198 for(i
=(long)str
.size()-1;i
>=0;i
--)
200 if(str
[i
]->dat
==st
)return true;
205 void remove_string(const string
&st
)
208 for(i
=(long)str
.size()-1;i
>=0;i
--)
218 void operator=(stringvectst
&two
);
231 if(array
!=NULL
)delete[] array
;
236 void set_size_on_flag_num(long flagnum
)
238 if(flagnum
<=0)return;
240 set_size(((flagnum
-1)>>3)+1);
243 void set_size(long newsize
)
245 if(newsize
<=0)return;
247 if(array
!=NULL
)delete[] array
;
248 array
=new unsigned char[newsize
];
249 memset(array
,0,sizeof(unsigned char)*newsize
);
256 if(slotnum
<=0)return;
258 if(array
!=NULL
)memset(array
,0,sizeof(unsigned char)*slotnum
);
261 void copy_from(flagarrayst
&src
)
267 set_size(src
.slotnum
);
268 memmove(array
,src
.array
,sizeof(unsigned char)*slotnum
);
272 bool has_flag(long checkflag
)
275 unsigned char addbit
;
276 if(get_slot_and_addbit_uchar(addbit
,slot
,checkflag
,slotnum
))
278 return (array
[slot
]&addbit
)!=0;
283 void add_flag(long checkflag
)
286 unsigned char addbit
;
287 if(get_slot_and_addbit_uchar(addbit
,slot
,checkflag
,slotnum
))
293 void toggle_flag(long checkflag
)
296 unsigned char addbit
;
297 if(get_slot_and_addbit_uchar(addbit
,slot
,checkflag
,slotnum
))
303 void remove_flag(long checkflag
)
306 unsigned char addbit
;
307 if(get_slot_and_addbit_uchar(addbit
,slot
,checkflag
,slotnum
))
309 array
[slot
]&=~addbit
;
313 void write_file(file_compressorst
&filecomp
)
315 filecomp
.write_file(slotnum
);
319 for(ind
=0;ind
<slotnum
;ind
++)filecomp
.write_file(array
[ind
]);
323 void read_file(file_compressorst
&filecomp
,long loadversion
)
326 filecomp
.read_file(newsl
);
329 //AVOID UNNECESSARY DELETE/NEW
330 if(array
!=NULL
&&slotnum
!=newsl
)
333 array
=new unsigned char[newsl
];
335 if(array
==NULL
)array
=new unsigned char[newsl
];
338 for(ind
=0;ind
<newsl
;ind
++)filecomp
.read_file(array
[ind
]);
350 unsigned char *array
;
356 #define COLOR_BLACK 0
358 #define COLOR_GREEN 2
361 #define COLOR_MAGENTA 5
362 #define COLOR_YELLOW 6
363 #define COLOR_WHITE 7
382 COLOR_DATA_MAGENTA_R
,
383 COLOR_DATA_MAGENTA_G
,
384 COLOR_DATA_MAGENTA_B
,
391 #define TILEFLAG_DEAD BIT1
392 #define TILEFLAG_ROTATE BIT2
393 #define TILEFLAG_PIXRECT BIT3
394 #define TILEFLAG_HORFLIP BIT4
395 #define TILEFLAG_VERFLIP BIT5
396 #define TILEFLAG_LINE BIT6
397 #define TILEFLAG_RECT BIT7
398 #define TILEFLAG_BUFFER_DRAW BIT8
399 #define TILEFLAG_MODEL_PERSPECTIVE BIT9
400 #define TILEFLAG_MODEL_ORTHO BIT10
401 #define TILEFLAG_MODEL_TRANSLATE BIT11
402 #define TILEFLAG_LINE_3D BIT12
415 texture_bo() { bo
= tbo
= 0; }
418 glDeleteBuffers(1, &bo
);
419 glDeleteTextures(1, &tbo
);
424 void buffer(GLvoid
*ptr
, GLsizeiptr sz
) {
426 glGenBuffersARB(1, &bo
);
427 glGenTextures(1, &tbo
);
428 glBindBufferARB(GL_TEXTURE_BUFFER_ARB
, bo
);
429 glBufferDataARB(GL_TEXTURE_BUFFER_ARB
, sz
, ptr
, GL_STATIC_DRAW_ARB
);
432 void bind(GLenum texture_unit
, GLenum type
) {
433 glActiveTexture(texture_unit
);
434 glBindTexture(GL_TEXTURE_BUFFER_ARB
, tbo
);
435 glTexBufferARB(GL_TEXTURE_BUFFER_ARB
, type
, bo
);
438 GLuint
texnum() { return tbo
; }
444 std::ostringstream lines
;
446 std::ostringstream header
;
447 void load(const string
&filename
) {
448 this->filename
= filename
;
449 std::ifstream
file(filename
.c_str());
451 getline(file
, version
);
452 header
<< version
<< std::endl
;
453 while (file
.good()) {
456 lines
<< line
<< std::endl
;
460 GLuint
upload(GLenum type
) {
461 GLuint shader
= glCreateShader(type
);
462 string lines_done
= lines
.str(), header_done
= header
.str();
464 ptrs
[0] = header_done
.c_str();
465 ptrs
[1] = "#line 1 0\n";
466 ptrs
[2] = lines_done
.c_str();
467 glShaderSource(shader
, 3, ptrs
, NULL
);
468 glCompileShader(shader
);
469 // Let's see if this compiled correctly..
471 glGetShaderiv(shader
, GL_COMPILE_STATUS
, &status
);
472 if (status
== GL_FALSE
) { // ..no. Check the compilation log.
474 glGetShaderiv(shader
, GL_INFO_LOG_LENGTH
, &log_size
);
475 //errorlog << filename << " preprocessed source:" << std::endl;
476 std::cerr
<< filename
<< " preprocessed source:" << std::endl
;
477 //errorlog << header_done << "#line 1 0\n" << lines_done;
478 std::cerr
<< header_done
<< "#line 1 0\n" << lines_done
;
479 //errorlog << filename << " shader compilation log (" << log_size << "):" << std::endl;
480 std::cerr
<< filename
<< " shader compilation log (" << log_size
<< "):" << std::endl
;
481 char *buf
= new char[log_size
];
482 glGetShaderInfoLog(shader
, log_size
, NULL
, buf
);
483 //errorlog << buf << std::endl;
484 std::cerr
<< buf
<< std::endl
;
487 MessageBox(NULL
, "Shader compilation failed; details in errorlog.txt", "Critical error", MB_OK
);
496 class text_info_elementst
499 virtual string
get_string()
504 virtual long get_long()
509 virtual ~text_info_elementst(){}
512 class text_info_element_stringst
: public text_info_elementst
515 virtual string
get_string()
519 text_info_element_stringst(const string
&newstr
)
528 class text_info_element_longst
: public text_info_elementst
531 virtual long get_long()
535 text_info_element_longst(long nval
)
547 svector
<text_info_elementst
*> element
;
551 while(element
.size()>0)
558 string
get_string(int e
)
560 if(e
<0||e
>=element
.size())
570 return element
[e
]->get_string();
575 if(e
<0||e
>=element
.size())
583 return element
[e
]->get_long();
592 class text_system_file_infost
598 static text_system_file_infost
*add_file_info(const string
&newf
,long newi
,char newft
)
600 return new text_system_file_infost(newf
,newi
,newft
);
603 void initialize_info();
604 void get_text(text_infost
&text
);
605 void get_specific_text(text_infost
&text
,long num
);
611 text_system_file_infost(const string
&newf
,long newi
,char newft
)
623 void register_file_fixed(const string
&file_name
,int32_t index
,char token
,char initialize
)
625 text_system_file_infost
*tsfi
=text_system_file_infost::add_file_info(file_name
,index
,token
);
626 if(initialize
)tsfi
->initialize_info();
627 file_info
.push_back(tsfi
);
629 void register_file(const string
&file_name
,int32_t &index
,char token
,char initialize
)
632 for(t
=(int32_t)file_info
.size()-1;t
>=0;t
--)
634 if(file_info
[t
]->filename
==file_name
)
636 //RESET CALLING INDEX AND BAIL IF THIS FILE IS ALREADY IN THE SYSTEM
637 index
=file_info
[t
]->index
;
642 text_system_file_infost
*tsfi
=text_system_file_infost::add_file_info(file_name
,index
,token
);
643 if(initialize
)tsfi
->initialize_info();
644 file_info
.push_back(tsfi
);
646 void initialize_system()
649 for(t
=(int32_t)file_info
.size()-1;t
>=0;t
--)file_info
[t
]->initialize_info();
651 void get_text(int32_t index
,text_infost
&text
)
654 for(t
=(int32_t)file_info
.size()-1;t
>=0;t
--)
656 if(file_info
[t
]->index
==index
)
658 file_info
[t
]->get_text(text
);
663 void get_text(const string
&file_name
,text_infost
&text
)
666 for(t
=(int32_t)file_info
.size()-1;t
>=0;t
--)
668 if(file_info
[t
]->filename
==file_name
)
670 file_info
[t
]->get_text(text
);
675 void get_specific_text(int32_t index
,text_infost
&text
,int32_t num
)
678 for(t
=(int32_t)file_info
.size()-1;t
>=0;t
--)
680 if(file_info
[t
]->index
==index
)
682 file_info
[t
]->get_specific_text(text
,num
);
690 while(file_info
.size()>0)
698 svector
<text_system_file_infost
*> file_info
;
701 class curses_text_boxst
706 void add_paragraph(stringvectst
&src
,int32_t para_width
);
707 void add_paragraph(const string
&src
,int32_t para_width
);
709 void read_file(file_compressorst
&filecomp
,int32_t loadversion
)
711 text
.read_file(filecomp
,loadversion
);
713 void write_file(file_compressorst
&filecomp
)
715 text
.write_file(filecomp
);
723 #define COPYTEXTUREFLAG_HORFLIP BIT1
724 #define COPYTEXTUREFLAG_VERFLIP BIT2
726 #define ENABLERFLAG_RENDER BIT1
727 #define ENABLERFLAG_MAXFPS BIT2
730 // GL texture positions
732 GLfloat left
, right
, top
, bottom
;
736 // Covers every allowed permutation of text
739 unsigned char fg
, bg
, bold
;
741 bool operator< (const ttf_id
&other
) const {
742 if (fg
!= other
.fg
) return fg
< other
.fg
;
743 if (bg
!= other
.bg
) return bg
< other
.bg
;
744 if (bold
!= other
.bold
) return bold
< other
.bold
;
745 return text
< other
.text
;
748 bool operator== (const ttf_id
&other
) const {
749 return fg
== other
.fg
&& bg
== other
.bg
&& bold
== other
.bold
&& text
== other
.text
;
754 template<> struct hash
<ttf_id
> {
755 size_t operator()(ttf_id val
) const {
756 // Not the ideal hash function, but it'll do. And it's better than GCC's. id? Seriously?
757 return hash
<string
>()(val
.text
) + val
.fg
+ (val
.bg
<< 4) + (val
.bold
<< 8);
761 // Being a texture catalog interface, with opengl, sdl and truetype capability
764 friend class enablerst
;
765 friend class renderer_opengl
;
767 vector
<SDL_Surface
*> raws
;
769 long add_texture(SDL_Surface
*);
772 GLuint gl_catalog
; // texture catalog gennum
773 struct gl_texpos
*gl_texpos
; // Texture positions in the GL catalog, if any
776 // Initialize state variables
784 for (auto it
= raws
.cbegin(); it
!= raws
.cend(); ++it
)
785 SDL_FreeSurface(*it
);
790 // Upload in-memory textures to the GPU
791 // When textures are uploaded, any alteration to a texture
792 // is automatically reflected in the uploaded copy - eg. it's replaced.
793 // This is very expensive in opengl mode. Don't do it often.
794 void upload_textures();
795 // Also, you really should try to remove uploaded textures before
796 // deleting a window, in case of driver memory leaks.
797 void remove_uploaded_textures();
798 // Returns the most recent texture data
799 SDL_Surface
*get_texture_data(long pos
);
801 long clone_texture(long src
);
802 // Remove all color, but not transparency
803 void grayscale_texture(long pos
);
804 // Loads dimx*dimy textures from a file, assuming all tiles
805 // are equally large and arranged in a grid
806 // Texture positions are saved in row-major order to tex_pos
807 // If convert_magenta is true and the file does not have built-in transparency,
808 // any magenta (255,0,255 RGB) is converted to full transparency
809 // The calculated size of individual tiles is saved to disp_x, disp_y
810 void load_multi_pdim(const string
&filename
,long *tex_pos
,long dimx
,long dimy
,
811 bool convert_magenta
,
812 long *disp_x
, long *disp_y
);
813 // Loads a single texture from a file, returning the handle
814 long load(const string
&filename
, bool convert_magenta
);
815 // To delete a texture..
816 void delete_texture(long pos
);
825 typedef struct { // Window Creation Info
826 char* title
; // Window Title
828 int height
; // Height
829 int bitsPerPixel
; // Bits Per Pixel
830 BOOL isFullScreen
; // FullScreen?
831 } GL_WindowInit
; // GL_WindowInit
833 typedef struct { // Contains Information Vital To A Window
834 GL_WindowInit init
; // Window Init
835 BOOL isVisible
; // Window Visible?
836 } GL_Window
; // GL_Window
840 enum zoom_commands
{ zoom_in
, zoom_out
, zoom_reset
, zoom_fullscreen
, zoom_resetgrid
};
843 struct texture_fullid
{
848 bool operator< (const struct texture_fullid
&other
) const {
849 if (texpos
!= other
.texpos
) return texpos
< other
.texpos
;
850 if (r
!= other
.r
) return r
< other
.r
;
851 if (g
!= other
.g
) return g
< other
.g
;
852 if (b
!= other
.b
) return b
< other
.b
;
853 if (br
!= other
.br
) return br
< other
.br
;
854 if (bg
!= other
.bg
) return bg
< other
.bg
;
855 return bb
< other
.bb
;
859 typedef int texture_ttfid
; // Just the texpos
862 void cleanup_arrays();
864 unsigned char *screen
;
866 char *screentexpos_addcolor
;
867 unsigned char *screentexpos_grayscale
;
868 unsigned char *screentexpos_cf
;
869 unsigned char *screentexpos_cbr
;
870 // For partial printing:
871 unsigned char *screen_old
;
872 long *screentexpos_old
;
873 char *screentexpos_addcolor_old
;
874 unsigned char *screentexpos_grayscale_old
;
875 unsigned char *screentexpos_cf_old
;
876 unsigned char *screentexpos_cbr_old
;
878 void gps_allocate(int x
, int y
);
879 Either
<texture_fullid
,texture_ttfid
> screen_to_texid(int x
, int y
);
882 virtual void update_tile(int x
, int y
) = 0;
883 virtual void update_all() = 0;
884 virtual void render() = 0;
885 virtual void set_fullscreen() {} // Should read from enabler.is_fullscreen()
886 virtual void zoom(zoom_commands cmd
) {};
887 virtual void resize(int w
, int h
) = 0;
888 virtual void grid_resize(int w
, int h
) = 0;
893 screentexpos_addcolor
= NULL
;
894 screentexpos_grayscale
= NULL
;
895 screentexpos_cf
= NULL
;
896 screentexpos_cbr
= NULL
;
898 screentexpos_old
= NULL
;
899 screentexpos_addcolor_old
= NULL
;
900 screentexpos_grayscale_old
= NULL
;
901 screentexpos_cf_old
= NULL
;
902 screentexpos_cbr_old
= NULL
;
904 virtual ~renderer() {
907 virtual bool get_mouse_coords(int &x
, int &y
) = 0;
908 virtual bool uses_opengl() { return false; };
911 class enablerst
: public enabler_inputst
914 friend class renderer_2d_base
;
915 friend class renderer_2d
;
916 friend class renderer_opengl
;
917 friend class renderer_curses
;
920 stack
<pair
<int,int> > overridden_grid_sizes
;
922 class renderer
*renderer
;
923 void eventLoop_SDL();
925 void eventLoop_ncurses();
928 // Framerate calculations
929 int calculated_fps
, calculated_gfps
;
930 queue
<int> frame_timings
, gframe_timings
; // Milisecond lengths of the last few frames
931 int frame_sum
, gframe_sum
;
932 int frame_last
, gframe_last
; // SDL_GetTick returns
933 void do_update_fps(queue
<int> &q
, int &sum
, int &last
, int &calc
);
941 // Frame timing calculations
945 float outstanding_frames
, outstanding_gframes
;
949 enum cmd_t
{ pause
, start
, render
, inc
, set_fps
} cmd
;
950 int val
; // If async_inc, number of extra frames to run. If set_fps, current value of fps.
952 async_cmd(cmd_t c
) { cmd
= c
; }
956 enum msg_t
{ quit
, complete
, set_fps
, set_gfps
, push_resize
, pop_resize
, reset_textures
} msg
;
958 int fps
; // set_fps, set_gfps
959 struct { // push_resize
964 async_msg(msg_t m
) { msg
= m
; }
967 unsigned int async_frames
; // Number of frames the async thread has been asked to run
969 Chan
<async_cmd
> async_tobox
; // Messages to the simulation thread
970 Chan
<async_msg
> async_frombox
; // Messages from the simulation thread, and acknowledgements of those to
971 Chan
<zoom_commands
> async_zoom
; // Zoom commands (from the simulation thread)
972 Chan
<void> async_fromcomplete
; // Barrier for async_msg requests that require acknowledgement
974 Uint32 renderer_threadid
;
977 void pause_async_loop();
979 void unpause_async_loop() {
980 struct async_cmd cmd
;
981 cmd
.cmd
= async_cmd::start
;
982 async_tobox
.write(cmd
);
989 float ccolor
[16][3]; // The curses-RGB mapping used for non-curses display modes
992 unsigned long flag
; // ENABLERFLAG_RENDER, ENABLERFLAG_MAXFPS
994 int loop(string cmdline
);
998 // Framerate interface
999 void set_fps(int fps
);
1000 void set_gfps(int gfps
);
1001 int get_fps() { return (int)fps
; }
1002 int get_gfps() { return (int)gfps
; }
1003 int calculate_fps(); // Calculate the actual provided (G)FPS
1004 int calculate_gfps();
1006 // Mouse interface, such as it is
1007 char mouse_lbut
,mouse_rbut
,mouse_lbut_down
,mouse_rbut_down
,mouse_lbut_lift
,mouse_rbut_lift
;
1008 char tracking_on
; // Whether we're tracking the mouse or not
1010 // OpenGL state (wrappers)
1011 class textures textures
; // Font/graphics texture catalog
1013 GLsync sync
; // Rendering barrier
1015 void reset_textures() {
1016 async_frombox
.write(async_msg(async_msg::reset_textures
));
1018 bool uses_opengl() {
1019 if (!renderer
) return false;
1020 return renderer
->uses_opengl();
1023 // Grid-size interface
1024 void override_grid_size(int w
, int h
); // Pick a /particular/ grid-size
1025 void release_grid_size(); // Undoes override_grid_size
1026 void zoom_display(zoom_commands command
);
1029 // Window management
1030 bool is_fullscreen() { return fullscreen
; }
1031 void toggle_fullscreen() {
1032 fullscreen
= !fullscreen
;
1033 async_zoom
.write(zoom_fullscreen
);
1037 text_systemst text_system
;
1039 // TOADY: MOVE THESE TO "FRAMERATE INTERFACE"
1040 MVar
<int> simticks
, gputicks
;
1041 Uint32 clock
; // An *approximation* of the current time for use in garbage collection thingies, updated every frame or so.
1045 // Function prototypes for deep-DF calls
1046 char beginroutine();
1050 extern enablerst enabler
;