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.
11 #include <SDL/SDL_thread.h>
13 # include <SDL_ttf/SDL_ttf.h>
14 # include <SDL_image/SDL_image.h>
16 # include <SDL/SDL_ttf.h>
17 # include <SDL/SDL_image.h>
48 #include "enabler_input.h"
74 #define BIT18 131072UL
75 #define BIT19 262144UL
76 #define BIT20 524288UL
77 #define BIT21 1048576UL
78 #define BIT22 2097152UL
79 #define BIT23 4194304UL
80 #define BIT24 8388608UL
81 #define BIT25 16777216UL
82 #define BIT26 33554432UL
83 #define BIT27 67108864UL
84 #define BIT28 134217728UL
85 #define BIT29 268435456UL
86 #define BIT30 536870912UL
87 #define BIT31 1073741824UL
88 #define BIT32 2147483648UL
92 #define GAME_TITLE_STRING "Dwarf Fortress"
94 char get_slot_and_addbit_uchar(unsigned char &addbit
,long &slot
,long checkflag
,long slotnum
);
105 svector
<pstringst
*> str
;
107 void add_string(const string
&st
)
109 pstringst
*newp
=new pstringst
;
114 long add_unique_string(const string
&st
)
117 for(i
=(long)str
.size()-1;i
>=0;i
--)
119 if(str
[i
]->dat
==st
)return i
;
122 return (long)str
.size()-1;
125 void add_string(const char *st
)
129 pstringst
*newp
=new pstringst
;
135 void insert_string(long k
,const string
&st
)
137 pstringst
*newp
=new pstringst
;
139 if(str
.size()>k
)str
.insert(k
,newp
);
140 else str
.push_back(newp
);
157 void read_file(file_compressorst
&filecomp
,long loadversion
)
160 filecomp
.read_file(dummy
);
166 str
[s
]=new pstringst
;
167 filecomp
.read_file(str
[s
]->dat
);
170 void write_file(file_compressorst
&filecomp
)
172 long dummy
=str
.size();
173 filecomp
.write_file(dummy
);
178 filecomp
.write_file(str
[s
]->dat
);
182 void copy_from(stringvectst
&src
)
186 str
.resize(src
.str
.size());
189 for(s
=(long)src
.str
.size()-1;s
>=0;s
--)
191 str
[s
]=new pstringst
;
192 str
[s
]->dat
=src
.str
[s
]->dat
;
196 bool has_string(const string
&st
)
199 for(i
=(long)str
.size()-1;i
>=0;i
--)
201 if(str
[i
]->dat
==st
)return true;
206 void remove_string(const string
&st
)
209 for(i
=(long)str
.size()-1;i
>=0;i
--)
219 void operator=(stringvectst
&two
);
232 if(array
!=NULL
)delete[] array
;
237 void set_size_on_flag_num(long flagnum
)
239 if(flagnum
<=0)return;
241 set_size(((flagnum
-1)>>3)+1);
244 void set_size(long newsize
)
246 if(newsize
<=0)return;
248 if(array
!=NULL
)delete[] array
;
249 array
=new unsigned char[newsize
];
250 memset(array
,0,sizeof(unsigned char)*newsize
);
257 if(slotnum
<=0)return;
259 if(array
!=NULL
)memset(array
,0,sizeof(unsigned char)*slotnum
);
262 void copy_from(flagarrayst
&src
)
268 set_size(src
.slotnum
);
269 memmove(array
,src
.array
,sizeof(unsigned char)*slotnum
);
273 bool has_flag(long checkflag
)
276 unsigned char addbit
;
277 if(get_slot_and_addbit_uchar(addbit
,slot
,checkflag
,slotnum
))
279 return (array
[slot
]&addbit
)!=0;
284 void add_flag(long checkflag
)
287 unsigned char addbit
;
288 if(get_slot_and_addbit_uchar(addbit
,slot
,checkflag
,slotnum
))
294 void toggle_flag(long checkflag
)
297 unsigned char addbit
;
298 if(get_slot_and_addbit_uchar(addbit
,slot
,checkflag
,slotnum
))
304 void remove_flag(long checkflag
)
307 unsigned char addbit
;
308 if(get_slot_and_addbit_uchar(addbit
,slot
,checkflag
,slotnum
))
310 array
[slot
]&=~addbit
;
314 void write_file(file_compressorst
&filecomp
)
316 filecomp
.write_file(slotnum
);
320 for(ind
=0;ind
<slotnum
;ind
++)filecomp
.write_file(array
[ind
]);
324 void read_file(file_compressorst
&filecomp
,long loadversion
)
327 filecomp
.read_file(newsl
);
330 //AVOID UNNECESSARY DELETE/NEW
331 if(array
!=NULL
&&slotnum
!=newsl
)
334 array
=new unsigned char[newsl
];
336 if(array
==NULL
)array
=new unsigned char[newsl
];
339 for(ind
=0;ind
<newsl
;ind
++)filecomp
.read_file(array
[ind
]);
351 unsigned char *array
;
357 #define COLOR_BLACK 0
359 #define COLOR_GREEN 2
362 #define COLOR_MAGENTA 5
363 #define COLOR_YELLOW 6
364 #define COLOR_WHITE 7
383 COLOR_DATA_MAGENTA_R
,
384 COLOR_DATA_MAGENTA_G
,
385 COLOR_DATA_MAGENTA_B
,
392 #define TILEFLAG_DEAD BIT1
393 #define TILEFLAG_ROTATE BIT2
394 #define TILEFLAG_PIXRECT BIT3
395 #define TILEFLAG_HORFLIP BIT4
396 #define TILEFLAG_VERFLIP BIT5
397 #define TILEFLAG_LINE BIT6
398 #define TILEFLAG_RECT BIT7
399 #define TILEFLAG_BUFFER_DRAW BIT8
400 #define TILEFLAG_MODEL_PERSPECTIVE BIT9
401 #define TILEFLAG_MODEL_ORTHO BIT10
402 #define TILEFLAG_MODEL_TRANSLATE BIT11
403 #define TILEFLAG_LINE_3D BIT12
416 texture_bo() { bo
= tbo
= 0; }
419 glDeleteBuffers(1, &bo
);
420 glDeleteTextures(1, &tbo
);
425 void buffer(GLvoid
*ptr
, GLsizeiptr sz
) {
427 glGenBuffersARB(1, &bo
);
428 glGenTextures(1, &tbo
);
429 glBindBufferARB(GL_TEXTURE_BUFFER_ARB
, bo
);
430 glBufferDataARB(GL_TEXTURE_BUFFER_ARB
, sz
, ptr
, GL_STATIC_DRAW_ARB
);
433 void bind(GLenum texture_unit
, GLenum type
) {
434 glActiveTexture(texture_unit
);
435 glBindTexture(GL_TEXTURE_BUFFER_ARB
, tbo
);
436 glTexBufferARB(GL_TEXTURE_BUFFER_ARB
, type
, bo
);
439 GLuint
texnum() { return tbo
; }
445 std::ostringstream lines
;
447 std::ostringstream header
;
448 void load(const string
&filename
) {
449 this->filename
= filename
;
450 std::ifstream
file(filename
.c_str());
452 getline(file
, version
);
453 header
<< version
<< std::endl
;
454 while (file
.good()) {
457 lines
<< line
<< std::endl
;
461 GLuint
upload(GLenum type
) {
462 GLuint shader
= glCreateShader(type
);
463 string lines_done
= lines
.str(), header_done
= header
.str();
465 ptrs
[0] = header_done
.c_str();
466 ptrs
[1] = "#line 1 0\n";
467 ptrs
[2] = lines_done
.c_str();
468 glShaderSource(shader
, 3, ptrs
, NULL
);
469 glCompileShader(shader
);
470 // Let's see if this compiled correctly..
472 glGetShaderiv(shader
, GL_COMPILE_STATUS
, &status
);
473 if (status
== GL_FALSE
) { // ..no. Check the compilation log.
475 glGetShaderiv(shader
, GL_INFO_LOG_LENGTH
, &log_size
);
476 //errorlog << filename << " preprocessed source:" << std::endl;
477 std::cerr
<< filename
<< " preprocessed source:" << std::endl
;
478 //errorlog << header_done << "#line 1 0\n" << lines_done;
479 std::cerr
<< header_done
<< "#line 1 0\n" << lines_done
;
480 //errorlog << filename << " shader compilation log (" << log_size << "):" << std::endl;
481 std::cerr
<< filename
<< " shader compilation log (" << log_size
<< "):" << std::endl
;
482 char *buf
= new char[log_size
];
483 glGetShaderInfoLog(shader
, log_size
, NULL
, buf
);
484 //errorlog << buf << std::endl;
485 std::cerr
<< buf
<< std::endl
;
488 MessageBox(NULL
, "Shader compilation failed; details in errorlog.txt", "Critical error", MB_OK
);
497 class text_info_elementst
500 virtual string
get_string()
505 virtual long get_long()
510 virtual ~text_info_elementst(){}
513 class text_info_element_stringst
: public text_info_elementst
516 virtual string
get_string()
520 text_info_element_stringst(const string
&newstr
)
529 class text_info_element_longst
: public text_info_elementst
532 virtual long get_long()
536 text_info_element_longst(long nval
)
548 svector
<text_info_elementst
*> element
;
552 while(element
.size()>0)
559 string
get_string(int e
)
561 if(e
<0||e
>=element
.size())
571 return element
[e
]->get_string();
576 if(e
<0||e
>=element
.size())
584 return element
[e
]->get_long();
593 class text_system_file_infost
599 static text_system_file_infost
*add_file_info(const string
&newf
,long newi
,char newft
)
601 return new text_system_file_infost(newf
,newi
,newft
);
604 void initialize_info();
605 void get_text(text_infost
&text
);
606 void get_specific_text(text_infost
&text
,long num
);
612 text_system_file_infost(const string
&newf
,long newi
,char newft
)
624 void register_file_fixed(const string
&file_name
,int32_t index
,char token
,char initialize
)
626 text_system_file_infost
*tsfi
=text_system_file_infost::add_file_info(file_name
,index
,token
);
627 if(initialize
)tsfi
->initialize_info();
628 file_info
.push_back(tsfi
);
630 void register_file(const string
&file_name
,int32_t &index
,char token
,char initialize
)
633 for(t
=(int32_t)file_info
.size()-1;t
>=0;t
--)
635 if(file_info
[t
]->filename
==file_name
)
637 //RESET CALLING INDEX AND BAIL IF THIS FILE IS ALREADY IN THE SYSTEM
638 index
=file_info
[t
]->index
;
643 text_system_file_infost
*tsfi
=text_system_file_infost::add_file_info(file_name
,index
,token
);
644 if(initialize
)tsfi
->initialize_info();
645 file_info
.push_back(tsfi
);
647 void initialize_system()
650 for(t
=(int32_t)file_info
.size()-1;t
>=0;t
--)file_info
[t
]->initialize_info();
652 void get_text(int32_t index
,text_infost
&text
)
655 for(t
=(int32_t)file_info
.size()-1;t
>=0;t
--)
657 if(file_info
[t
]->index
==index
)
659 file_info
[t
]->get_text(text
);
664 void get_text(const string
&file_name
,text_infost
&text
)
667 for(t
=(int32_t)file_info
.size()-1;t
>=0;t
--)
669 if(file_info
[t
]->filename
==file_name
)
671 file_info
[t
]->get_text(text
);
676 void get_specific_text(int32_t index
,text_infost
&text
,int32_t num
)
679 for(t
=(int32_t)file_info
.size()-1;t
>=0;t
--)
681 if(file_info
[t
]->index
==index
)
683 file_info
[t
]->get_specific_text(text
,num
);
691 while(file_info
.size()>0)
699 svector
<text_system_file_infost
*> file_info
;
702 class curses_text_boxst
707 void add_paragraph(stringvectst
&src
,int32_t para_width
);
708 void add_paragraph(const string
&src
,int32_t para_width
);
710 void read_file(file_compressorst
&filecomp
,int32_t loadversion
)
712 text
.read_file(filecomp
,loadversion
);
714 void write_file(file_compressorst
&filecomp
)
716 text
.write_file(filecomp
);
724 #define COPYTEXTUREFLAG_HORFLIP BIT1
725 #define COPYTEXTUREFLAG_VERFLIP BIT2
727 #define ENABLERFLAG_RENDER BIT1
728 #define ENABLERFLAG_MAXFPS BIT2
731 // GL texture positions
733 GLfloat left
, right
, top
, bottom
;
737 // Covers every allowed permutation of text
740 unsigned char fg
, bg
, bold
;
742 bool operator< (const ttf_id
&other
) const {
743 if (fg
!= other
.fg
) return fg
< other
.fg
;
744 if (bg
!= other
.bg
) return bg
< other
.bg
;
745 if (bold
!= other
.bold
) return bold
< other
.bold
;
746 return text
< other
.text
;
749 bool operator== (const ttf_id
&other
) const {
750 return fg
== other
.fg
&& bg
== other
.bg
&& bold
== other
.bold
&& text
== other
.text
;
755 template<> struct hash
<ttf_id
> {
756 size_t operator()(ttf_id val
) const {
757 // Not the ideal hash function, but it'll do. And it's better than GCC's. id? Seriously?
758 return hash
<string
>()(val
.text
) + val
.fg
+ (val
.bg
<< 4) + (val
.bold
<< 8);
762 // Being a texture catalog interface, with opengl, sdl and truetype capability
765 friend class enablerst
;
766 friend class renderer_opengl
;
768 vector
<SDL_Surface
*> raws
;
770 long add_texture(SDL_Surface
*);
773 GLuint gl_catalog
; // texture catalog gennum
774 struct gl_texpos
*gl_texpos
; // Texture positions in the GL catalog, if any
776 uint32_t gl_catalog_abi_dummy
;
777 void* gl_texpos_abi_dummy
;
780 // Initialize state variables
788 for (auto it
= raws
.cbegin(); it
!= raws
.cend(); ++it
)
789 SDL_FreeSurface(*it
);
794 // Upload in-memory textures to the GPU
795 // When textures are uploaded, any alteration to a texture
796 // is automatically reflected in the uploaded copy - eg. it's replaced.
797 // This is very expensive in opengl mode. Don't do it often.
798 void upload_textures();
799 // Also, you really should try to remove uploaded textures before
800 // deleting a window, in case of driver memory leaks.
801 void remove_uploaded_textures();
802 // Returns the most recent texture data
803 SDL_Surface
*get_texture_data(long pos
);
805 long clone_texture(long src
);
806 // Remove all color, but not transparency
807 void grayscale_texture(long pos
);
808 // Loads dimx*dimy textures from a file, assuming all tiles
809 // are equally large and arranged in a grid
810 // Texture positions are saved in row-major order to tex_pos
811 // If convert_magenta is true and the file does not have built-in transparency,
812 // any magenta (255,0,255 RGB) is converted to full transparency
813 // The calculated size of individual tiles is saved to disp_x, disp_y
814 void load_multi_pdim(const string
&filename
,long *tex_pos
,long dimx
,long dimy
,
815 bool convert_magenta
,
816 long *disp_x
, long *disp_y
);
817 // Loads a single texture from a file, returning the handle
818 long load(const string
&filename
, bool convert_magenta
);
819 // To delete a texture..
820 void delete_texture(long pos
);
829 typedef struct { // Window Creation Info
830 char* title
; // Window Title
832 int height
; // Height
833 int bitsPerPixel
; // Bits Per Pixel
834 BOOL isFullScreen
; // FullScreen?
835 } GL_WindowInit
; // GL_WindowInit
837 typedef struct { // Contains Information Vital To A Window
838 GL_WindowInit init
; // Window Init
839 BOOL isVisible
; // Window Visible?
840 } GL_Window
; // GL_Window
844 enum zoom_commands
{ zoom_in
, zoom_out
, zoom_reset
, zoom_fullscreen
, zoom_resetgrid
};
847 struct texture_fullid
{
852 bool operator< (const struct texture_fullid
&other
) const {
853 if (texpos
!= other
.texpos
) return texpos
< other
.texpos
;
854 if (r
!= other
.r
) return r
< other
.r
;
855 if (g
!= other
.g
) return g
< other
.g
;
856 if (b
!= other
.b
) return b
< other
.b
;
857 if (br
!= other
.br
) return br
< other
.br
;
858 if (bg
!= other
.bg
) return bg
< other
.bg
;
859 return bb
< other
.bb
;
863 typedef int texture_ttfid
; // Just the texpos
866 void cleanup_arrays();
868 unsigned char *screen
;
870 char *screentexpos_addcolor
;
871 unsigned char *screentexpos_grayscale
;
872 unsigned char *screentexpos_cf
;
873 unsigned char *screentexpos_cbr
;
874 // For partial printing:
875 unsigned char *screen_old
;
876 long *screentexpos_old
;
877 char *screentexpos_addcolor_old
;
878 unsigned char *screentexpos_grayscale_old
;
879 unsigned char *screentexpos_cf_old
;
880 unsigned char *screentexpos_cbr_old
;
882 void gps_allocate(int x
, int y
);
883 Either
<texture_fullid
,texture_ttfid
> screen_to_texid(int x
, int y
);
886 virtual void update_tile(int x
, int y
) = 0;
887 virtual void update_all() = 0;
888 virtual void render() = 0;
889 virtual void set_fullscreen() {} // Should read from enabler.is_fullscreen()
890 virtual void zoom(zoom_commands cmd
) {};
891 virtual void resize(int w
, int h
) = 0;
892 virtual void grid_resize(int w
, int h
) = 0;
897 screentexpos_addcolor
= NULL
;
898 screentexpos_grayscale
= NULL
;
899 screentexpos_cf
= NULL
;
900 screentexpos_cbr
= NULL
;
902 screentexpos_old
= NULL
;
903 screentexpos_addcolor_old
= NULL
;
904 screentexpos_grayscale_old
= NULL
;
905 screentexpos_cf_old
= NULL
;
906 screentexpos_cbr_old
= NULL
;
908 virtual ~renderer() {
911 virtual bool get_mouse_coords(int &x
, int &y
) = 0;
912 virtual bool uses_opengl() { return false; };
915 class enablerst
: public enabler_inputst
918 friend class renderer_2d_base
;
919 friend class renderer_2d
;
920 friend class renderer_opengl
;
921 friend class renderer_curses
;
924 stack
<pair
<int,int> > overridden_grid_sizes
;
926 class renderer
*renderer
;
927 void eventLoop_SDL();
929 void eventLoop_ncurses();
932 // Framerate calculations
933 int calculated_fps
, calculated_gfps
;
934 queue
<int> frame_timings
, gframe_timings
; // Milisecond lengths of the last few frames
935 int frame_sum
, gframe_sum
;
936 int frame_last
, gframe_last
; // SDL_GetTick returns
937 void do_update_fps(queue
<int> &q
, int &sum
, int &last
, int &calc
);
945 // Frame timing calculations
949 float outstanding_frames
, outstanding_gframes
;
953 enum cmd_t
{ pause
, start
, render
, inc
, set_fps
} cmd
;
954 int val
; // If async_inc, number of extra frames to run. If set_fps, current value of fps.
956 async_cmd(cmd_t c
) { cmd
= c
; }
960 enum msg_t
{ quit
, complete
, set_fps
, set_gfps
, push_resize
, pop_resize
, reset_textures
} msg
;
962 int fps
; // set_fps, set_gfps
963 struct { // push_resize
968 async_msg(msg_t m
) { msg
= m
; }
971 unsigned int async_frames
; // Number of frames the async thread has been asked to run
973 Chan
<async_cmd
> async_tobox
; // Messages to the simulation thread
974 Chan
<async_msg
> async_frombox
; // Messages from the simulation thread, and acknowledgements of those to
975 Chan
<zoom_commands
> async_zoom
; // Zoom commands (from the simulation thread)
976 Chan
<void> async_fromcomplete
; // Barrier for async_msg requests that require acknowledgement
978 Uint32 renderer_threadid
;
981 void pause_async_loop();
983 void unpause_async_loop() {
984 struct async_cmd cmd
;
985 cmd
.cmd
= async_cmd::start
;
986 async_tobox
.write(cmd
);
993 float ccolor
[16][3]; // The curses-RGB mapping used for non-curses display modes
996 unsigned long flag
; // ENABLERFLAG_RENDER, ENABLERFLAG_MAXFPS
998 int loop(string cmdline
);
1002 // Framerate interface
1003 void set_fps(int fps
);
1004 void set_gfps(int gfps
);
1005 int get_fps() { return (int)fps
; }
1006 int get_gfps() { return (int)gfps
; }
1007 int calculate_fps(); // Calculate the actual provided (G)FPS
1008 int calculate_gfps();
1010 // Mouse interface, such as it is
1011 char mouse_lbut
,mouse_rbut
,mouse_lbut_down
,mouse_rbut_down
,mouse_lbut_lift
,mouse_rbut_lift
;
1012 char tracking_on
; // Whether we're tracking the mouse or not
1014 // OpenGL state (wrappers)
1015 class textures textures
; // Font/graphics texture catalog
1017 GLsync sync
; // Rendering barrier
1019 uint32_t sync_abi_dummy
;
1021 void reset_textures() {
1022 async_frombox
.write(async_msg(async_msg::reset_textures
));
1024 bool uses_opengl() {
1025 if (!renderer
) return false;
1026 return renderer
->uses_opengl();
1029 // Grid-size interface
1030 void override_grid_size(int w
, int h
); // Pick a /particular/ grid-size
1031 void release_grid_size(); // Undoes override_grid_size
1032 void zoom_display(zoom_commands command
);
1035 // Window management
1036 bool is_fullscreen() { return fullscreen
; }
1037 void toggle_fullscreen() {
1038 fullscreen
= !fullscreen
;
1039 async_zoom
.write(zoom_fullscreen
);
1043 text_systemst text_system
;
1045 // TOADY: MOVE THESE TO "FRAMERATE INTERFACE"
1046 MVar
<int> simticks
, gputicks
;
1047 Uint32 clock
; // An *approximation* of the current time for use in garbage collection thingies, updated every frame or so.
1051 // Function prototypes for deep-DF calls
1052 char beginroutine();
1056 extern enablerst enabler
;