diff --git a/osx/boe.graphics.cpp b/osx/boe.graphics.cpp index 79754814..7fbcfdf8 100644 --- a/osx/boe.graphics.cpp +++ b/osx/boe.graphics.cpp @@ -52,12 +52,12 @@ extern std::shared_ptr text_sbar,item_sbar,shop_sbar; extern sf::Texture bg_gworld; extern RECT sbar_rect,item_sbar_rect,shop_sbar_rect,startup_top; extern RECT talk_area_rect, word_place_rect; -extern RECT map_pat[]; +extern tessel_ref_t map_pat[]; extern location store_anim_ul; extern long register_flag; extern long ed_flag,ed_key; extern bool fast_bang; -extern RECT bg[]; +extern tessel_ref_t bg[]; extern cScenario scenario; extern cUniverse univ; extern cCustomGraphics spec_scen_g; @@ -159,7 +159,7 @@ char spot_seen[9][9]; char anim_str[60]; location anim_str_loc; -extern RECT bw_pats[6]; +extern tessel_ref_t bw_pats[6]; extern short combat_posing_monster , current_working_monster ; // 0-5 PC 100 + x - monster x bool supressing_some_spaces = false; @@ -621,7 +621,7 @@ void redraw_screen(int refresh) { void put_background() { - RECT bg_pict; + tessel_ref_t bg_pict; if(overall_mode == MODE_STARTUP) bg_pict = bg[4]; @@ -645,7 +645,7 @@ void put_background() bg_pict = bg[8]; else bg_pict = bg[13]; } - tileImage(mainPtr, RECT(mainPtr), bg_gworld, bg_pict); + tileImage(mainPtr, RECT(mainPtr), bg_pict); } void draw_buttons(short mode) diff --git a/osx/boe.newgraph.cpp b/osx/boe.newgraph.cpp index ee78a190..bf987a7c 100644 --- a/osx/boe.newgraph.cpp +++ b/osx/boe.newgraph.cpp @@ -47,7 +47,7 @@ short monsters_faces[190] = { extern location ul; extern RECT windRect; extern long anim_ticks; -extern RECT bg[]; +extern tessel_ref_t bg[]; extern sf::RenderWindow mainPtr; extern short town_type,which_combat_type; extern eGameMode overall_mode; @@ -72,7 +72,7 @@ extern location store_anim_ul; extern char light_area[13][13]; extern short terrain_there[9][9]; extern char unexplored_area[13][13]; -extern RECT bw_pats[6]; +extern tessel_ref_t bw_pats[6]; extern short combat_posing_monster , current_working_monster ; // 0-5 PC 100 + x - monster x extern short store_talk_face_pic; extern cScenario scenario; @@ -172,7 +172,7 @@ void apply_unseen_mask() to_rect = base_rect; to_rect.offset(-28 + i * 28,-36 + 36 * j); to_rect |= big_to; - tileImage(mainPtr, to_rect, bg_gworld, bw_pats[3], sf::BlendAlpha); + tileImage(mainPtr, to_rect, bw_pats[3], sf::BlendAlpha); //PaintRoundRect(&to_rect,4,4); for (k = i - 2; k < i + 1; k++) for (l = j - 2; l < j + 1; l++) @@ -777,7 +777,7 @@ void draw_shop_graphics(bool pressed,RECT clip_area_rect) area_rect = RECT(talk_gworld); frame_rect(talk_gworld, area_rect, sf::Color::Black); area_rect.inset(1,1); - tileImage(talk_gworld, area_rect,bg_gworld,bg[12]); + tileImage(talk_gworld, area_rect,bg[12]); frame_rect(talk_gworld, shop_frame, sf::Color::Black); @@ -1135,7 +1135,7 @@ void place_talk_str(std::string str_to_place,std::string str_to_place2,short col area_rect = RECT(talk_gworld); frame_rect(talk_gworld, area_rect, sf::Color::Black); area_rect.inset(1,1); - tileImage(talk_gworld, area_rect,bg_gworld,bg[12]); + tileImage(talk_gworld, area_rect,bg[12]); // Put help button // TODO: Reimplement this with a cButton diff --git a/osx/boe.text.cpp b/osx/boe.text.cpp index 220d95c3..46f516e7 100644 --- a/osx/boe.text.cpp +++ b/osx/boe.text.cpp @@ -68,7 +68,7 @@ extern short which_item_page[6]; //extern CursHandle sword_curs; extern std::shared_ptr text_sbar,item_sbar; extern location store_anim_ul; -extern RECT bg[]; +extern tessel_ref_t bg[]; extern short dest_personalities[40]; extern location source_locs[6]; extern location dest_locs[40] ; @@ -138,9 +138,9 @@ void put_pc_screen() pc_stats_gworld.setActive(); // First clean up gworld with pretty patterns - tileImage(pc_stats_gworld, erase_rect,bg_gworld,bg[6]); + tileImage(pc_stats_gworld, erase_rect,bg[6]); for (i = 0; i < 3; i++) - tileImage(pc_stats_gworld, small_erase_rects[i],bg_gworld,bg[7]); + tileImage(pc_stats_gworld, small_erase_rects[i],bg[7]); TextStyle style; style.font = FONT_BOLD; @@ -259,16 +259,16 @@ void put_item_screen(short screen_num,short suppress_buttons) item_stats_gworld.setActive(); // First clean up gworld with pretty patterns - tileImage(item_stats_gworld, erase_rect,bg_gworld,bg[6]); + tileImage(item_stats_gworld, erase_rect,bg[6]); if (suppress_buttons == 0) for (i = 0; i < 6; i++) - tileImage(item_stats_gworld, item_screen_button_rects[i],bg_gworld,bg[7]); - tileImage(item_stats_gworld, upper_frame_rect,bg_gworld,bg[7]); + tileImage(item_stats_gworld, item_screen_button_rects[i],bg[7]); + tileImage(item_stats_gworld, upper_frame_rect,bg[7]); // Draw buttons at bottom if (suppress_buttons == 0) { for (i = 0; i < 6; i++) - tileImage(item_stats_gworld, item_screen_button_rects[i],bg_gworld,bg[7]); + tileImage(item_stats_gworld, item_screen_button_rects[i],bg[7]); } item_offset = item_sbar->getPosition(); @@ -1355,7 +1355,7 @@ void print_buf () text_area_gworld.setActive(); // First clean up gworld with pretty patterns - tileImage(text_area_gworld, erase_rect,bg_gworld,bg[6]); + tileImage(text_area_gworld, erase_rect,bg[6]); ctrl_val = 58 - text_sbar->getPosition(); start_print_point = buf_pointer - LINES_IN_TEXT_WIN - ctrl_val; @@ -1432,71 +1432,6 @@ void Draw_Some_Item (sf::Texture& src_gworld, RECT src_rect, sf::RenderTarget& t } } - -//void rect_draw_some_item (GWorldPtr src_gworld, RECT src_rect, GWorldPtr targ_gworld, -//RECT targ_rect, char masked, short main_win) -//// masked; // if 10 - make AddOver -//// main_win; // if 2, drawing onto dialog -//{ -// PixMapHandle test1, test2; -// const BitMap * store_dest; -// GrafPtr cur_port; -// RGBColor store_color; -// -// GetPort(&cur_port); -// if (src_gworld == NULL) { -// if (main_win == 0) { -// SetPort ( targ_gworld); -// PaintRect(&targ_rect); -// SetPort (cur_port); -// } -// else PaintRect(&targ_rect); -// return; -// } -// if (main_win == 2) { -// GetBackColor(&store_color); -// BackColor(whiteColor); -// } -// -// store_dest = GetPortBitMapForCopyBits(cur_port); -// -// test1 = GetPortPixMap(src_gworld); -// -// if (main_win == 1) -// OffsetRect(&targ_rect,ul.h,ul.v); -// -// LockPixels(test1); -// if (main_win == 0) { -// test2 = GetPortPixMap(targ_gworld); -// LockPixels(test2); -// if (masked == 1) -// CopyBits ( (BitMap *) *test1 , -// (BitMap *) *test2 , -// &src_rect, &targ_rect, -// transparent , NULL); -// else CopyBits ( (BitMap *) *test1 , -// (BitMap *) *test2 , -// &src_rect, &targ_rect, -// (masked == 10) ? addOver : 0, NULL); -// UnlockPixels(test2); -// } -// else { -// if (masked == 1) -// CopyBits ( (BitMap *) *test1 , -// store_dest , -// &src_rect, &targ_rect, -// transparent , NULL); -// else CopyBits ( (BitMap *) *test1 , -// store_dest , -// &src_rect, &targ_rect, -// (masked == 10) ? addOver : 0, NULL); -// } -// UnlockPixels(test1); -// if (main_win == 2) -// RGBBackColor(&store_color); -// SetPort(cur_port); -//} - // TODO: This seems to duplicate logic found in graphtool to get a rect from a picture index RECT coord_to_rect(short i,short j) { @@ -1516,159 +1451,6 @@ void make_cursor_sword() set_cursor(sword_curs); } -//short string_length(char *str) -//{ -// short text_len[257]; -// short total_width = 0,i,len; -// char p_str[256]; -// -// for (i = 0; i < 257; i++) -// text_len[i]= 0; -// -// strcpy((char *) p_str,str); -// c2pstr(p_str); -// MeasureText(256,p_str,text_len); -// len = strlen((char *)str); -// -// for (i = 0; i < 257; i++) -// if ((text_len[i] > total_width) && (i <= len)) -// total_width = text_len[i]; -// return total_width; -//} - - -//void char_win_draw_string(WindowPtr dest_window,RECT dest_rect,char *str,short mode,short line_height) -//{ -// char_port_draw_string(GetWindowPort(dest_window), dest_rect, str, mode, line_height); -//} -// -// -//void char_port_draw_string(GrafPtr dest_window,RECT dest_rect,char *str,short mode,short line_height) -//{ -// char store_s[256]; -// -// strcpy((char *) store_s,str); -// win_draw_string( dest_window, dest_rect,store_s, mode, line_height); -// -//} - -// mode: 0 - align up and left, 1 - center on one line -// str is a c string, 256 characters -// uses current font -//void win_draw_string(GrafPtr dest_window,RECT dest_rect,Str255 str,short mode,short line_height) -//{ -// GrafPtr old_port; -// const char* p_str,str_to_draw,str_to_draw2,c_str; -// char null_s[256] = " "; -// short str_len,i; -// short last_line_break = 0,last_word_break = 0,on_what_line = 0; -// short text_len[257]; -// short total_width = 0; -// bool force_skip = false; -// RgnHandle current_clip; -// short adjust_x = 0,adjust_y = 0; -// -// if (dest_window == GetWindowPort(mainPtr)) { -// adjust_x = ul.h; adjust_y = ul.v; -// } -// strcpy((char *) p_str,(char *) str); -// strcpy((char *) c_str,(char *) str); -// c2pstr(p_str); -// for (i = 0; i < 257; i++) -// text_len[i]= 0; -// MeasureText(256,p_str,text_len); -// str_len = (short) strlen((char *)str); -// if (str_len == 0) { -// return; -// } -// -// GetPort(&old_port); -// SetPort(dest_window); -// -// //FrameRect(&dest_rect); -// -// current_clip = NewRgn(); -// GetClip(current_clip); -// -// dest_rect.bottom += 5; -// //ClipRect(&dest_rect); -// dest_rect.bottom -= 5; -// -// -// for (i = 0; i < 257; i++) -// if ((text_len[i] > total_width) && (i <= str_len)) -// total_width = text_len[i]; -// if ((mode == 0) && (total_width < dest_rect.right - dest_rect.left)) -// mode = 2; -// for (i = 0; i < 257; i++) -// if ((i <= str_len) && (c_str[i] == '|') && (mode == 2)) -// mode = 0; -// -// -// switch (mode) { -// case 0: -// MoveTo(dest_rect.left + 1 + adjust_x, dest_rect.top + 1 + line_height * on_what_line + adjust_y + 9); -// for (i = 0;text_len[i] != text_len[i + 1], i < str_len;i++) { -// if (((text_len[i] - text_len[last_line_break] > (dest_rect.right - dest_rect.left - 6)) -// && (last_word_break > last_line_break)) || (c_str[i] == '|')) { -// if (c_str[i] == '|') { -// c_str[i] = ' '; -// force_skip = true; -// last_word_break = i + 1; -// } -// sprintf((char *)str_to_draw,"%s",(char *)null_s); -// strncpy ((char *) str_to_draw,(char *) c_str + last_line_break,(size_t) (last_word_break - last_line_break - 1)); -// sprintf((char *)str_to_draw2," %s",str_to_draw); -// str_to_draw2[0] = (char) strlen((char *)str_to_draw); -// DrawString(str_to_draw2); -// on_what_line++; -// MoveTo(dest_rect.left + 1 + adjust_x, dest_rect.top + 1 + line_height * on_what_line + adjust_y + 9); -// last_line_break = last_word_break; -// if (force_skip == true) { -// force_skip = false; -// i++; -// //last_line_break++; -// //last_word_break++; -// } -// } -// if (c_str[i] == ' ') -// last_word_break = i + 1; -// if (on_what_line == LINES_IN_TEXT_WIN - 1) -// i = 10000; -// } -// -// if (i - last_line_break > 1) { -// strcpy((char *)str_to_draw,(char *)null_s); -// strncpy ((char *) str_to_draw,(char *) c_str + last_line_break,(size_t) (i - last_line_break)); -// sprintf((char *)str_to_draw2," %s",str_to_draw); -// if (strlen((char *) str_to_draw2) > 3) { -// str_to_draw2[0] = (char) strlen((char *)str_to_draw); -// DrawString(str_to_draw2); -// } -// } -// break; -// case 1: -// MoveTo((dest_rect.right + dest_rect.left) / 2 - (4 * total_width) / 9 + adjust_x, -// (dest_rect.bottom + dest_rect.top - line_height) / 2 + 9 + adjust_y); -// DrawText(p_str,1,p_str[0]); -// //DrawString(p_str); -// break; -// case 2: -// MoveTo(dest_rect.left + 1 + adjust_x, -// dest_rect.top + 1 + adjust_y + 9); -// DrawString(p_str); -// break; -// case 3: -// MoveTo(dest_rect.left + 1 + adjust_x, -// dest_rect.top + 1 + adjust_y + 9 + (dest_rect.bottom - dest_rect.top) / 6); -// DrawString(p_str); -// break; -// } -// SetClip(current_clip); -// DisposeRgn(current_clip); -// SetPort(old_port); -//} - short calc_day() { return (short) ((univ.party.age) / 3700) + 1; diff --git a/osx/boe.town.cpp b/osx/boe.town.cpp index 369d80cb..bdefecbf 100644 --- a/osx/boe.town.cpp +++ b/osx/boe.town.cpp @@ -76,7 +76,7 @@ extern sf::RenderTexture map_gworld; extern sf::Texture small_ter_gworld; // In the 0..65535 range, this colour was {65535,65535,52428} sf::Color parchment = {255,255,205}; -extern RECT map_pat[]; +extern tessel_ref_t map_pat[]; // TODO: Add blue cave graphics to these arrays? unsigned char map_pats[256] = { @@ -1516,7 +1516,7 @@ void draw_map(bool need_refresh) { map_graphic_placed[kludge.x / 8][kludge.y] | (unsigned char)(s_pow(2,kludge.x % 8)); } } - tileImage(mini_map, draw_rect,bg_gworld,map_pat[((pic >= 400) ? anim_map_pats[pic - 400] : map_pats[pic]) - 1]); + tileImage(mini_map, draw_rect,map_pat[((pic >= 400) ? anim_map_pats[pic - 400] : map_pats[pic]) - 1]); break; } //OffsetRect(&ter_temp_from, @@ -1540,7 +1540,7 @@ void draw_map(bool need_refresh) { style.pointSize = 10;; the_rect = RECT(mini_map); - tileImage(mini_map, the_rect,bg_gworld,bg[4]); + tileImage(mini_map, the_rect,bg[4]); cPict theGraphic(mini_map); theGraphic.setBounds(dlogpicrect); theGraphic.setPict(21, PIC_DLOG); diff --git a/osx/dialogxml/button.cpp b/osx/dialogxml/button.cpp index 82e24d3d..90bfdb6e 100644 --- a/osx/dialogxml/button.cpp +++ b/osx/dialogxml/button.cpp @@ -80,7 +80,7 @@ void cButton::draw(){ // TODO: How is it supposed to know it's a default button when this fact is stored in the dialog, not the button? if(key.spec && key.k == key_enter) drawFrame(2,frameStyle); // frame default button, to provide a visual cue that it's the default }else{ - tileImage(*inWindow,frame,bg_gworld,bg[parent->getBg()]); + tileImage(*inWindow,frame,bg[parent->getBg()]); } } @@ -251,7 +251,7 @@ void cLed::draw(){ to_rect.left = frame.left + 18; // Possibly could be 20 win_draw_string(*inWindow,to_rect,lbl,eTextMode::LEFT_TOP,style); }else{ - tileImage(*inWindow,frame,bg_gworld,bg[parent->getBg()]); + tileImage(*inWindow,frame,bg[parent->getBg()]); } } diff --git a/osx/dialogxml/dialog.cpp b/osx/dialogxml/dialog.cpp index d9a04fc0..6a644e3b 100644 --- a/osx/dialogxml/dialog.cpp +++ b/osx/dialogxml/dialog.cpp @@ -927,14 +927,24 @@ void cDialog::run(){ tabOrder[0].second->triggerFocusHandler(*this, tabOrder[0].first, false); currentFocus = tabOrder[0].first; } + // Sometimes it seems like the Cocoa menu handling clobbers the active rendering context. + // For whatever reason, delaying 100 milliseconds appears to fix this. + sf::sleep(sf::milliseconds(100)); win.create(sf::VideoMode(winRect.width(), winRect.height()), "Dialog", sf::Style::Titlebar); win.setActive(); win.setVisible(true); makeFrontWindow(win); ModalSession dlog(win); + paintTimer.restart(); animTimer.restart(); + draw(); while(dialogNotToast){ - draw(); + // TODO: This is just a hack to prevent the constant flickering. + // All it actually does is slow the flickering to non-blinding frequency. + if(paintTimer.getElapsedTime().asMilliseconds() > 500) { + draw(); + paintTimer.restart(); + } dlog.pumpEvents(); if(!win.pollEvent(currentEvent)) continue; location where; @@ -1375,7 +1385,7 @@ bool cDialog::doAnimations = false; void cDialog::draw(){ win.setActive(); - tileImage(win,winRect,bg_gworld,::bg[bg]); + tileImage(win,winRect,::bg[bg]); if(doAnimations && animTimer.getElapsedTime().asMilliseconds() >= 500) { cPict::advanceAnim(); animTimer.restart(); diff --git a/osx/dialogxml/dialog.h b/osx/dialogxml/dialog.h index 5e1355ba..89624ade 100644 --- a/osx/dialogxml/dialog.h +++ b/osx/dialogxml/dialog.h @@ -170,7 +170,7 @@ private: std::string defaultButton; boost::any result; std::string fname; - sf::Clock animTimer; + sf::Clock animTimer, paintTimer; friend class cControl; }; diff --git a/osx/dialogxml/pict.cpp b/osx/dialogxml/pict.cpp index 352c0e68..68c731a7 100644 --- a/osx/dialogxml/pict.cpp +++ b/osx/dialogxml/pict.cpp @@ -539,7 +539,7 @@ void cPict::draw(){ if(!visible){ // Erase it rect.inset(-3, -3); - tileImage(*inWindow,rect,bg_gworld,bg[parent->getBg()]); + tileImage(*inWindow,rect,bg[parent->getBg()]); return; } if(picNum < 0) { // Just fill with black diff --git a/osx/dialogxml/scrollbar.cpp b/osx/dialogxml/scrollbar.cpp index 39c9dacb..d7206ca5 100644 --- a/osx/dialogxml/scrollbar.cpp +++ b/osx/dialogxml/scrollbar.cpp @@ -12,6 +12,7 @@ #include "mathutil.h" sf::Texture cScrollbar::scroll_gw; +tessel_ref_t cScrollbar::bar_tessel[2]; cScrollbar::cScrollbar(cDialog& parent) : cControl(CTRL_SCROLL, parent) {} @@ -19,6 +20,10 @@ cScrollbar::cScrollbar(sf::RenderWindow& parent) : cControl(CTRL_SCROLL, parent) void cScrollbar::init() { scroll_gw.loadFromImage(*ResMgr::get("dlogscroll")); + RECT bar_rect = {0,48,16,64}; + bar_tessel[0] = prepareForTiling(scroll_gw, bar_rect); + bar_rect.offset(0,16); + bar_tessel[1] = prepareForTiling(scroll_gw, bar_rect); } bool cScrollbar::isClickable(){ @@ -149,7 +154,7 @@ sf::Color cScrollbar::getColour() throw(xUnsupportedProp) { void cScrollbar::draw() { if(!isVisible()) return; - static const RECT up_rect = {0,0,16,16}, down_rect = {0,16,16,32}, thumb_rect = {0,32,16,48}, bar_rect = {0,48,16,64}; + static const RECT up_rect = {0,0,16,16}, down_rect = {0,16,16,32}, thumb_rect = {0,32,16,48}; int bar_height = frame.height() - 32; inWindow->setActive(); RECT draw_rect = frame, from_rect = up_rect; @@ -160,10 +165,8 @@ void cScrollbar::draw() { if(pos > 0) { draw_rect.top = draw_rect.bottom; draw_rect.height() = pos * (bar_height - 16) / max; - from_rect = bar_rect; - if(depressed && pressedPart == PART_PGUP) - from_rect.offset(0,16); - tileImage(*inWindow, draw_rect, scroll_gw, from_rect); + bool pressed = depressed && pressedPart == PART_PGUP; + tileImage(*inWindow, draw_rect, bar_tessel[pressed]); } draw_rect.top = draw_rect.bottom; draw_rect.height() = 16; @@ -174,10 +177,8 @@ void cScrollbar::draw() { if(pos < max) { draw_rect.top = draw_rect.bottom; draw_rect.bottom = frame.bottom - 16; - from_rect = bar_rect; - if(depressed && pressedPart == PART_PGDN) - from_rect.offset(0,16); - tileImage(*inWindow, draw_rect, scroll_gw, from_rect); + bool pressed = depressed && pressedPart == PART_PGDN; + tileImage(*inWindow, draw_rect, bar_tessel[pressed]); } draw_rect = frame; draw_rect.top = draw_rect.bottom - 16; diff --git a/osx/dialogxml/scrollbar.h b/osx/dialogxml/scrollbar.h index aa8809ce..62e0ab07 100644 --- a/osx/dialogxml/scrollbar.h +++ b/osx/dialogxml/scrollbar.h @@ -13,6 +13,7 @@ /// Scrollbar-related classes and types. #include "control.h" +#include "graphtool.h" /// A simple vertical scrollbar. /// This has no coupling with scrollable data; that must be handled externally by @@ -28,6 +29,7 @@ class cScrollbar : public cControl { } pressedPart; click_callback_t onClick; static sf::Texture scroll_gw; + static tessel_ref_t bar_tessel[2]; public: /// @copydoc cDialog::init() static void init(); diff --git a/osx/pcedit/pc.graphics.cpp b/osx/pcedit/pc.graphics.cpp index 3fccadea..d134c31e 100644 --- a/osx/pcedit/pc.graphics.cpp +++ b/osx/pcedit/pc.graphics.cpp @@ -261,7 +261,7 @@ void draw_main_screen() RECT source_rect, dest_rec,dest_rect; RECT reg_rect; - tileImage(mainPtr,whole_win_rect,bg_gworld,bg[12]); // fill whole window with background texture + tileImage(mainPtr,whole_win_rect,bg[12]); // fill whole window with background texture dest_rec = source_rect = title_from; // initializes, to draw title // title_from is a RECT constant dest_rec.offset(20,0); diff --git a/osx/scenedit/scen.graphics.cpp b/osx/scenedit/scen.graphics.cpp index cac2c34d..699709a4 100644 --- a/osx/scenedit/scen.graphics.cpp +++ b/osx/scenedit/scen.graphics.cpp @@ -87,7 +87,7 @@ sf::Texture roads_gworld; sf::Texture missiles_gworld; sf::Texture status_gworld; sf::Texture pc_gworld; -extern RECT map_pat[]; +extern tessel_ref_t map_pat[]; // begin new stuff RECT blue_button_from = {120,91,134,107}; @@ -388,7 +388,7 @@ void load_main_screen() { void redraw_screen() { RECT windRect(mainPtr); - tileImage(mainPtr,windRect,bg_gworld,bg[20]); + tileImage(mainPtr,windRect,bg[20]); draw_main_screen(); if (overall_mode < MODE_MAIN_SCREEN); draw_terrain(); @@ -414,7 +414,7 @@ void draw_main_screen() { frame_rect(mainPtr, draw_rect, sf::Color::Black); draw_rect.inset(1,1); - tileImage(mainPtr,draw_rect,bg_gworld,bg[17]); + tileImage(mainPtr,draw_rect,bg[17]); draw_rb(); right_sbar->draw(); @@ -437,7 +437,7 @@ void draw_lb() { short i; temp_rect.right = RIGHT_AREA_UL_X - 2; - tileImage(mainPtr,temp_rect,bg_gworld,bg[20]); + tileImage(mainPtr,temp_rect,bg[20]); for (i = 0; i < NLS; i++) draw_lb_slot(i,0); } @@ -446,7 +446,7 @@ void draw_lb() { void draw_lb_slot (short which,short mode) { RECT text_rect,from_rect; - tileImage(mainPtr,left_buttons[which][0],bg_gworld,bg[20]); + tileImage(mainPtr,left_buttons[which][0],bg[20]); if (left_button_status[which] == 0) return; text_rect = left_buttons[which][0]; @@ -487,7 +487,7 @@ void draw_rb_slot (short which,short mode) { if ((which < pos) || (which >= pos + NRSONPAGE)) return; - tileImage(mainPtr,right_buttons[which - pos],bg_gworld,bg[17]); + tileImage(mainPtr,right_buttons[which - pos],bg[17]); if (right_button_status[which] == 0) return; text_rect = right_buttons[which - pos]; @@ -506,7 +506,7 @@ void set_up_terrain_buttons() { RECT palette_from,palette_to = palette_button_base; - tileImage(terrain_buttons_gworld,terrain_buttons_rect,bg_gworld,bg[17]); + tileImage(terrain_buttons_gworld,terrain_buttons_rect,bg[17]); frame_rect(terrain_buttons_gworld, terrain_buttons_rect, sf::Color::Black); // first make terrain buttons @@ -611,7 +611,7 @@ void draw_terrain(){ return; if (cur_viewing_mode == 0) { - tileImage(ter_draw_gworld,terrain_rect,bg_gworld,bg[17]); + tileImage(ter_draw_gworld,terrain_rect,bg[17]); frame_rect(ter_draw_gworld, terrain_rect, sf::Color::Black); for (q = 0; q < 9; q++) for (r = 0; r < 9; r++) @@ -817,7 +817,7 @@ void draw_terrain(){ if (cur_viewing_mode == 1) { if (small_any_drawn == false) { - tileImage(ter_draw_gworld, terrain_rect,bg_gworld,bg[17]); + tileImage(ter_draw_gworld, terrain_rect,bg[17]); frame_rect(ter_draw_gworld, terrain_rect, sf::Color::Black); } for (q = 0; q < (editing_town ? town->max_dim() : 48); q++) @@ -926,7 +926,7 @@ void draw_items() { dest_rect.left += 5; dest_rect.right -= 5; } - rect_draw_some_item((pic_num < 45) ? items_gworld : tiny_obj_gworld, + rect_draw_some_item((pic_num < 55) ? items_gworld : tiny_obj_gworld, source_rect, ter_draw_gworld, dest_rect,sf::BlendAlpha); } } @@ -997,15 +997,15 @@ void draw_one_tiny_terrain_spot (short i,short j,ter_num_t terrain_to_draw) { switch (picture_wanted) { case 0: case 1: case 73: case 72: - tileImage(ter_draw_gworld, dest_rect,bg_gworld,map_pat[0]); + tileImage(ter_draw_gworld, dest_rect,map_pat[0]); break; case 2: case 3: case 4: - tileImage(ter_draw_gworld, dest_rect,bg_gworld,map_pat[1]); + tileImage(ter_draw_gworld, dest_rect,map_pat[1]); break; default: if ((picture_wanted < 170) && (map_pats[picture_wanted] > 0)) { - tileImage(ter_draw_gworld, dest_rect,bg_gworld,map_pat[map_pats[picture_wanted]]); + tileImage(ter_draw_gworld, dest_rect,map_pat[map_pats[picture_wanted]]); } else if (picture_wanted >= 1000) { graf_pos_ref(source_gworld, from_rect) = spec_scen_g.find_graphic(picture_wanted % 1000); @@ -1014,12 +1014,12 @@ void draw_one_tiny_terrain_spot (short i,short j,ter_num_t terrain_to_draw) { else if (picture_wanted >= 400) { source_gworld = &anim_gworld; picture_wanted -= 400; - if (picture_wanted == 0) tileImage(ter_draw_gworld, dest_rect,bg_gworld,map_pat[13]); - else if (picture_wanted == 4) tileImage(ter_draw_gworld, dest_rect,bg_gworld,map_pat[21]); - else if (picture_wanted == 7) tileImage(ter_draw_gworld, dest_rect,bg_gworld,map_pat[20]); - else if (picture_wanted == 8) tileImage(ter_draw_gworld, dest_rect,bg_gworld,map_pat[19]); - else if (picture_wanted == 9) tileImage(ter_draw_gworld, dest_rect,bg_gworld,map_pat[20]); - else if (picture_wanted == 10) tileImage(ter_draw_gworld, dest_rect,bg_gworld,map_pat[19]); + if (picture_wanted == 0) tileImage(ter_draw_gworld, dest_rect,map_pat[13]); + else if (picture_wanted == 4) tileImage(ter_draw_gworld, dest_rect,map_pat[21]); + else if (picture_wanted == 7) tileImage(ter_draw_gworld, dest_rect,map_pat[20]); + else if (picture_wanted == 8) tileImage(ter_draw_gworld, dest_rect,map_pat[19]); + else if (picture_wanted == 9) tileImage(ter_draw_gworld, dest_rect,map_pat[20]); + else if (picture_wanted == 10) tileImage(ter_draw_gworld, dest_rect,map_pat[19]); else { //source_rect.left = 112 * (picture_wanted / 5); //source_rect.right = source_rect.left + 28; @@ -1131,7 +1131,7 @@ void place_location() { erase_rect.right = RIGHT_AREA_WIDTH - 1; erase_rect.top = terrain_rects[255].top + 26 - 9;//12 - 9; erase_rect.bottom = erase_rect.top + 12; - tileImage(terrain_buttons_gworld, erase_rect,bg_gworld,bg[17]); + tileImage(terrain_buttons_gworld, erase_rect,bg[17]); //MoveTo(terrain_rects[255].left + 20 ,terrain_rects[255].top + 12); location moveTo(5 ,terrain_rects[255].top + 26); @@ -1157,7 +1157,7 @@ void place_location() { erase_rect.right = RIGHT_AREA_WIDTH - 1; erase_rect.top = terrain_rects[255].bottom + 117; erase_rect.bottom = RIGHT_AREA_HEIGHT + 6; - tileImage(terrain_buttons_gworld, erase_rect,bg_gworld,bg[17]); + tileImage(terrain_buttons_gworld, erase_rect,bg[17]); if (overall_mode < MODE_MAIN_SCREEN) { moveTo = location(5,terrain_rects[255].bottom + 129); @@ -1221,7 +1221,7 @@ void place_just_location() { erase_rect.right = RIGHT_AREA_WIDTH - 1; erase_rect.top = terrain_rects[255].top + 12 - 9; erase_rect.bottom = erase_rect.top + 12; - tileImage(terrain_buttons_gworld, erase_rect,bg_gworld,bg[17]); + tileImage(terrain_buttons_gworld, erase_rect,bg[17]); //MoveTo(terrain_rects[255].left + 20 ,terrain_rects[255].top + 12); location moveTo(5 ,terrain_rects[255].top + 26); diff --git a/osx/tools/graphtool.cpp b/osx/tools/graphtool.cpp index a27cb010..e104f588 100644 --- a/osx/tools/graphtool.cpp +++ b/osx/tools/graphtool.cpp @@ -16,16 +16,21 @@ #endif #include +#include #include #include #include "restypes.hpp" +#include "mathutil.h" using boost::math::constants::pi; -RECT bg[21]; -RECT map_pat[30]; -RECT bw_pats[6]; +RECT bg_rects[21]; +RECT map_pat_rects[30]; +RECT bw_rects[6]; +tessel_ref_t bg[21]; +tessel_ref_t map_pat[30]; +tessel_ref_t bw_pat[6]; sf::Texture bg_gworld; bool use_win_graphics = false; sf::Shader maskShader; @@ -33,6 +38,8 @@ extern fs::path progDir; // TODO: Shouldn't need this extern sf::RenderWindow mainPtr; +static void register_main_patterns(); + void init_graph_tool(){ fs::path shaderPath = progDir/"data"/"shaders"; fs::path fragPath = shaderPath/"mask.frag", vertPath = shaderPath/"mask.vert"; @@ -80,49 +87,48 @@ void init_graph_tool(){ 18,19,20,21,22,24,25,27, 28,29 }; -// for (i = 0; i < 21; i++) -// bg[i] = GetPixPat(128 + i); for(i = 0; i < 17; i++){ - bg[pat_i[i]] = {0,0,64,64}; - bg[pat_i[i]].offset(64 * pat_offs[i].x,64 * pat_offs[i].y); + bg_rects[pat_i[i]] = {0,0,64,64}; + bg_rects[pat_i[i]].offset(64 * pat_offs[i].x,64 * pat_offs[i].y); } - RECT tmp_rect = bg[19]; + RECT tmp_rect = bg_rects[19]; tmp_rect.offset(0, 64); - bg[0] = bg[1] = bg[18] = map_pat[7] = tmp_rect; - bg[0].right -= 32; - bg[0].bottom -= 32; - bg[1].left -= 32; - bg[1].bottom -= 32; - bg[18].right -= 32; - bg[18].top -= 32; - map_pat[7].left -= 32; - map_pat[7].top -= 32; + bg_rects[0] = bg_rects[1] = bg_rects[18] = map_pat_rects[7] = tmp_rect; + bg_rects[0].right -= 32; + bg_rects[0].bottom -= 32; + bg_rects[1].left -= 32; + bg_rects[1].bottom -= 32; + bg_rects[18].right -= 32; + bg_rects[18].top -= 32; + map_pat_rects[7].left -= 32; + map_pat_rects[7].top -= 32; tmp_rect.offset(0, 64); - map_pat[8] = map_pat[23] = map_pat[26] = tmp_rect; - map_pat[8].right -= 32; - map_pat[8].bottom -= 32; - map_pat[23].left -= 32; - map_pat[23].right -= 16; - map_pat[23].bottom -= 32; - map_pat[26].left -= 32 + 16; - map_pat[26].bottom -= 32; + map_pat_rects[8] = map_pat_rects[23] = map_pat_rects[26] = tmp_rect; + map_pat_rects[8].right -= 32; + map_pat_rects[8].bottom -= 32; + map_pat_rects[23].left -= 32; + map_pat_rects[23].right -= 16; + map_pat_rects[23].bottom -= 32; + map_pat_rects[26].left -= 32 + 16; + map_pat_rects[26].bottom -= 32; tmp_rect.offset(0, 64); - bg[7] = tmp_rect; - bg[7].bottom = bg[7].top + 16; + bg_rects[7] = tmp_rect; + bg_rects[7].bottom = bg_rects[7].top + 16; tmp_rect.offset(0, -32); tmp_rect.right = tmp_rect.left + 8; tmp_rect.bottom = tmp_rect.top + 8; for(i = 0; i < 26; i++){ - map_pat[map_i[i]] = tmp_rect; - map_pat[map_i[i]].offset(8 * (i % 8),8 * (i / 8)); + map_pat_rects[map_i[i]] = tmp_rect; + map_pat_rects[map_i[i]].offset(8 * (i % 8),8 * (i / 8)); // Note: 8 * (i / 8) != i, despite appearances, due to integer rounding } - tmp_rect = map_pat[29]; + tmp_rect = map_pat_rects[29]; for(i = 0; i < 6; i++) { tmp_rect.offset(8, 0); - bw_pats[i] = tmp_rect; + bw_rects[i] = tmp_rect; } bg_gworld.loadFromImage(*ResMgr::get("pixpats")); + register_main_patterns(); } static void rect_draw_some_item(const sf::Texture& src_gworld,RECT src_rect,sf::RenderTarget& targ_gworld,RECT targ_rect,sf::RenderStates mode); @@ -401,7 +407,7 @@ void draw_terrain(){ if (cur_viewing_mode == 0) { SetPort( ter_draw_gworld); - FillCRect(&terrain_rect,bg[6]); + FillCRect(&terrain_rect,bg_rects[6]); FrameRect(&terrain_rect); SetPortWindowPort(mainPtr); for (q = 0; q < 9; q++) @@ -617,7 +623,7 @@ void draw_terrain(){ if (cur_viewing_mode == 1) { SetPort( ter_draw_gworld); if (small_any_drawn == false) { - FillCRect(&terrain_rect,bg[6]); + FillCRect(&terrain_rect,bg_rects[6]); FrameRect(&terrain_rect); } for (q = 0; q < ((editing_town == true) ? max_dim[town_type] : 48); q++) @@ -1068,6 +1074,19 @@ void Region::offset(location off) { offset(off.x, off.y); } +RECT Region::getEnclosingRect() { + if(shapes.empty()) return RECT(); + RECT bounds = shapes[0]->getGlobalBounds(); + for(size_t i = 0; i < shapes.size(); i++) { + RECT shapeRect = shapes[i]->getGlobalBounds(); + if(shapeRect.top < bounds.top) bounds.top = shapeRect.top; + if(shapeRect.left < bounds.left) bounds.top = shapeRect.top; + if(shapeRect.bottom > bounds.bottom) bounds.top = shapeRect.top; + if(shapeRect.right > bounds.right) bounds.top = shapeRect.top; + } + return bounds; +} + // We can only use stencil buffer in the main window // Could request it in dialogs, but currently don't // SFML does not appear to allow requesting it for render textures @@ -1130,79 +1149,82 @@ Region& Region::operator-=(Region& other) { return *this; } -void tileImage(sf::RenderTarget& target, RECT area, sf::Texture& img, sf::BlendMode mode){ - bool saveRep = img.isRepeated(); - img.setRepeated(true); - sf::Vector2u imgSz = img.getSize(); - RECT clipArea = area; - area.left -= area.left % imgSz.x; - area.top -= area.top % imgSz.y; - area |= RECT(target); // Make sure we don't draw out of bounds +struct tessel_t { + sf::RenderTexture* tessel; + sf::Texture* img; + RECT srcRect; +}; - unsigned int hrep = int((double(area.width())/imgSz.x)+0.5); - unsigned int vrep = int((double(area.height())/imgSz.y)+0.5); - sf::RectangleShape tessel(sf::Vector2f(hrep*imgSz.x,vrep*imgSz.y)); - tessel.setTexture(&img); - tessel.setPosition(area.left, area.top); - sf::RenderStates renderMode(mode); - setActiveRenderTarget(target); - clip_rect(target, clipArea); - target.draw(tessel, renderMode); - undo_clip(target); - img.setRepeated(saveRep); +bool operator==(const tessel_ref_t& a, const tessel_ref_t& b) { + return a.key == b.key; } -void tileImage(sf::RenderTarget& target, RECT area, sf::Texture& img, RECT srcRect, sf::BlendMode mode){ - sf::RenderTexture temp; - temp.create(srcRect.width(), srcRect.height()); - temp.setRepeated(true); - RECT tesselRect(temp); - temp.setActive(); - rect_draw_some_item(img, srcRect, temp, tesselRect); - temp.display(); - RECT clipArea = area; - area.left -= area.left % tesselRect.width(); - area.top -= area.top % tesselRect.height(); - area |= RECT(target); // Make sure we don't draw out of bounds - - sf::RectangleShape tessel(sf::Vector2f(area.width(),area.height())); - tessel.setTexture(&temp.getTexture()); - tessel.setTextureRect(area); - tessel.setPosition(area.left, area.top); - sf::RenderStates renderMode(mode); - setActiveRenderTarget(target); - clip_rect(target, clipArea); - target.draw(tessel, renderMode); - undo_clip(target); +template<> struct std::hash { + size_t operator()(tessel_ref_t key) const { + return key.key; + } +}; + +std::unordered_map tiling_reservoir; +static int tessel_index = 0; + +tessel_ref_t prepareForTiling(sf::Texture& srcImg, RECT srcRect) { + tessel_ref_t ref = {tessel_index++}; + tiling_reservoir[ref].img = &srcImg; + tiling_reservoir[ref].srcRect = srcRect; + tiling_reservoir[ref].tessel = new sf::RenderTexture; + tiling_reservoir[ref].tessel->create(srcRect.width(), srcRect.height()); + RECT tesselRect(*tiling_reservoir[ref].tessel); + rect_draw_some_item(srcImg, srcRect, *tiling_reservoir[ref].tessel, tesselRect); + tiling_reservoir[ref].tessel->display(); + tiling_reservoir[ref].tessel->setRepeated(true); + return ref; } -#if 0 - -void tileImage(RgnHandle area, GWorldPtr img, RECT srcRect, short mode){ - GrafPtr cur_port; - GetPort(&cur_port); - const BitMap* drawDest = GetPortBitMapForCopyBits(cur_port); - PixMapHandle drawSource = GetPortPixMap(img); - - int srcWidth=srcRect.right-srcRect.left; - int srcHeight=srcRect.bottom-srcRect.top; - int x,y; - RECT bounds; - GetRegionBounds(area, &bounds); - bounds.left -= bounds.left % srcWidth; - bounds.top -= bounds.top % srcHeight; - unsigned int hrep = (int)((double(bounds.right-bounds.left)/srcWidth)+0.5); - unsigned int vrep = (int)((double(bounds.bottom-bounds.top)/srcHeight)+0.5); - for(unsigned int i=0; i<=hrep; i++){ - for(unsigned int j=0; j<=vrep; j++){ - x=bounds.left+i*srcWidth; - y=bounds.top+j*srcHeight; - RECT targetRect={y,x,y+srcHeight,x+srcWidth}; - CopyBits((BitMap*)*drawSource, drawDest,&srcRect,&targetRect,mode,area); +void flushTessels(sf::Texture& alteredImg) { + erase_if(tiling_reservoir, [&alteredImg](std::pair& kv) -> bool { + if(kv.second.img == &alteredImg) { + delete kv.second.tessel; + return true; } + return false; + }); + if(&alteredImg == &bg_gworld) + register_main_patterns(); +} + +static void register_main_patterns() { + for(int i = 0; i < 30; i++) { + if(i < 21) { + if(i < 6) { + bw_pat[i] = prepareForTiling(bg_gworld, bw_rects[i]); + } + bg[i] = prepareForTiling(bg_gworld, bg_rects[i]); + } + map_pat[i] = prepareForTiling(bg_gworld, map_pat_rects[i]); } } -#endif + +void tileImage(sf::RenderTarget& target, RECT area, tessel_ref_t tessel, sf::BlendMode mode) { + // First, set up a dictionary of all textures ever tiled. + // The key type is a pair. + // The value type is a Texture. + tessel_t& tesselInfo = tiling_reservoir[tessel]; + RECT clipArea = area; + area.left -= area.left % tesselInfo.srcRect.width(); + area.top -= area.top % tesselInfo.srcRect.height(); + area |= RECT(target); // Make sure we don't draw out of bounds + + sf::RectangleShape tesselShape(sf::Vector2f(area.width(),area.height())); + tesselShape.setTexture(&tesselInfo.tessel->getTexture()); + tesselShape.setTextureRect(area); + tesselShape.setPosition(area.left, area.top); + sf::RenderStates renderMode(mode); + setActiveRenderTarget(target); + clip_rect(target, clipArea); + target.draw(tesselShape, renderMode); + undo_clip(target); +} short can_see(location p1,location p2,std::function get_obscurity) { short storage = 0; diff --git a/osx/tools/graphtool.h b/osx/tools/graphtool.h index c572bbf8..f26bbd11 100644 --- a/osx/tools/graphtool.h +++ b/osx/tools/graphtool.h @@ -52,6 +52,7 @@ public: void offset(int x, int y); void offset(location off); Region& operator-=(Region& other); + RECT getEnclosingRect(); }; typedef unsigned short pic_num_t; @@ -85,6 +86,12 @@ struct snippet_t { bool hilited; }; +struct tessel_ref_t { + int key; +}; + +bool operator==(const tessel_ref_t& a, const tessel_ref_t& b); + enum class eTextMode { WRAP, CENTRE, @@ -106,8 +113,10 @@ short string_length(std::string str, TextStyle style); //void draw_terrain(); RECT calc_rect(short i, short j); void setActiveRenderTarget(sf::RenderTarget& where); -void tileImage(sf::RenderTarget& target, RECT area, sf::Texture& img, sf::BlendMode mode = sf::BlendNone); -void tileImage(sf::RenderTarget& target, RECT area, sf::Texture& img, RECT srcRect, sf::BlendMode mode = sf::BlendNone); +void flushTessels(sf::Texture& alteredImg); +tessel_ref_t prepareForTiling(sf::Texture& srcImg, RECT srcRect); +void tileImage(sf::RenderTarget& target, RECT area, tessel_ref_t tessel, sf::BlendMode mode = sf::BlendNone); +void tileImage(sf::RenderWindow& target, Region& rgn, tessel_ref_t tessel, sf::BlendMode mode = sf::BlendNone); void fill_rect(sf::RenderTarget& target, RECT rect, sf::Color colour); void frame_rect(sf::RenderTarget& target, RECT rect, sf::Color colour); void fill_circle(sf::RenderTarget& target, RECT rect, sf::Color colour); @@ -128,7 +137,7 @@ std::string get_str(std::string list, short j); #ifndef GRAPHTOOL_CPP extern m_pic_index_t m_pic_index[200]; -extern RECT bg[]; +extern tessel_ref_t bg[]; #endif #endif