1273 lines
37 KiB
C++
1273 lines
37 KiB
C++
/*
|
|
* graphtool.cpp
|
|
* BoE
|
|
*
|
|
* Created by Celtic Minstrel on 16/04/09.
|
|
*
|
|
*/
|
|
|
|
#define GRAPHTOOL_CPP
|
|
#include "graphtool.h"
|
|
|
|
#ifdef __APPLE__
|
|
#include <OpenGl/GL.h>
|
|
#else
|
|
#include <GL/GL.h>
|
|
#endif
|
|
|
|
#include <typeinfo>
|
|
#include <unordered_map>
|
|
#include <boost/filesystem.hpp>
|
|
#include <boost/math/constants/constants.hpp>
|
|
|
|
#include "restypes.hpp"
|
|
#include "mathutil.h"
|
|
|
|
using boost::math::constants::pi;
|
|
|
|
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;
|
|
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";
|
|
std::ifstream fin;
|
|
|
|
fin.open(fragPath.c_str());
|
|
if(!fin.good()) perror("Error loading fragment shader");
|
|
fin.seekg(0, std::ios::end);
|
|
int size = fin.tellg();
|
|
fin.seekg(0);
|
|
char* fbuf = new char[size + 1];
|
|
fbuf[size] = 0;
|
|
fin.read(fbuf, size);
|
|
fin.close();
|
|
|
|
fin.open(vertPath.c_str());
|
|
if(!fin.good()) perror("Error loading vertex shader");
|
|
fin.seekg(0, std::ios::end);
|
|
size = fin.tellg();
|
|
fin.seekg(0);
|
|
char* vbuf = new char[size + 1];
|
|
vbuf[size] = 0;
|
|
fin.read(vbuf, size);
|
|
|
|
if(!maskShader.loadFromMemory(vbuf, fbuf)) {
|
|
fprintf(stderr,"Error: Failed to load shaders from %s\nVertex:\n%s\nFragment:\n%s",shaderPath.c_str(),vbuf,fbuf);
|
|
}
|
|
delete[] fbuf;
|
|
delete[] vbuf;
|
|
int i;
|
|
// TODO: The duplication of location here shouldn't be necessary
|
|
static const location pat_offs[17] = {
|
|
location{0,3}, location{1,1}, location{2,1}, location{2,0},
|
|
location{3,0}, location{3,1}, location{1,3}, location{0,0},
|
|
location{0,2}, location{1,2}, location{0,1}, location{2,2},
|
|
location{2,3}, location{3,2}, location{1,0}, location{4,0}, location{3,3}
|
|
};
|
|
static const int pat_i[17] = {
|
|
2, 3, 4, 5, 6, 8, 9, 10,
|
|
11,12,13,14,15,16,17,19,20
|
|
};
|
|
static const int map_i[26] = {
|
|
0, 1, 2, 3, 4, 5, 6, 9,
|
|
10,11,12,13,14,15,16,17,
|
|
18,19,20,21,22,24,25,27,
|
|
28,29
|
|
};
|
|
for(i = 0; i < 17; i++){
|
|
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_rects[19];
|
|
tmp_rect.offset(0, 64);
|
|
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_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_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_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_rects[29];
|
|
for(i = 0; i < 6; i++) {
|
|
tmp_rect.offset(8, 0);
|
|
bw_rects[i] = tmp_rect;
|
|
}
|
|
bg_gworld.loadFromImage(*ResMgr::get<ImageRsrc>("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);
|
|
|
|
void rect_draw_some_item(sf::RenderTarget& targ_gworld,RECT targ_rect) {
|
|
fill_rect(targ_gworld, targ_rect, sf::Color::Black);
|
|
}
|
|
|
|
void rect_draw_some_item(const sf::Texture& src_gworld,RECT src_rect,sf::RenderTarget& targ_gworld,RECT targ_rect,sf::BlendMode mode){
|
|
rect_draw_some_item(src_gworld, src_rect, targ_gworld, targ_rect, sf::RenderStates(mode));
|
|
}
|
|
|
|
void rect_draw_some_item(const sf::Texture& src_gworld,RECT src_rect,sf::RenderTarget& targ_gworld,RECT targ_rect,sf::RenderStates mode) {
|
|
setActiveRenderTarget(targ_gworld);
|
|
sf::Sprite tile(src_gworld, src_rect);
|
|
tile.setPosition(targ_rect.left, targ_rect.top);
|
|
double xScale = targ_rect.width(), yScale = targ_rect.height();
|
|
xScale /= src_rect.width();
|
|
yScale /= src_rect.height();
|
|
tile.setScale(xScale, yScale);
|
|
targ_gworld.draw(tile, mode);
|
|
}
|
|
|
|
void rect_draw_some_item(const sf::Texture& src_gworld,RECT src_rect,RECT targ_rect,location offset, sf::BlendMode mode) {
|
|
targ_rect.offset(offset);
|
|
rect_draw_some_item(src_gworld,src_rect,mainPtr,targ_rect,mode);
|
|
}
|
|
|
|
void rect_draw_some_item(const sf::Texture& src_gworld,RECT src_rect,const sf::Texture& mask_gworld,RECT mask_rect,sf::RenderTarget& targ_gworld,RECT targ_rect) {
|
|
sf::RenderTexture src;
|
|
src.create(src_rect.width(), src_rect.height());
|
|
RECT dest_rect = src_rect;
|
|
dest_rect.offset(-dest_rect.left,-dest_rect.top);
|
|
rect_draw_some_item(src_gworld, src_rect, src, dest_rect);
|
|
src.display();
|
|
sf::RenderTexture mask;
|
|
mask.create(mask_rect.width(), mask_rect.height());
|
|
dest_rect = mask_rect;
|
|
dest_rect.offset(-dest_rect.left,-dest_rect.top);
|
|
rect_draw_some_item(mask_gworld, mask_rect, mask, dest_rect);
|
|
mask.display();
|
|
|
|
maskShader.setParameter("texture", sf::Shader::CurrentTexture);
|
|
maskShader.setParameter("mask", mask.getTexture());
|
|
rect_draw_some_item(src.getTexture(), dest_rect, targ_gworld, targ_rect, &maskShader);
|
|
}
|
|
|
|
void TextStyle::applyTo(sf::Text& text) {
|
|
switch(font) {
|
|
case FONT_PLAIN:
|
|
text.setFont(*ResMgr::get<FontRsrc>("plain"));
|
|
break;
|
|
case FONT_BOLD:
|
|
text.setFont(*ResMgr::get<FontRsrc>("bold"));
|
|
break;
|
|
case FONT_DUNGEON:
|
|
text.setFont(*ResMgr::get<FontRsrc>("dungeon"));
|
|
break;
|
|
case FONT_MAIDWORD:
|
|
text.setFont(*ResMgr::get<FontRsrc>("maidenword"));
|
|
break;
|
|
}
|
|
text.setCharacterSize(pointSize);
|
|
int style = sf::Text::Regular;
|
|
if(italic) style |= sf::Text::Italic;
|
|
if(underline) style |= sf::Text::Underlined;
|
|
text.setStyle(style);
|
|
text.setColor(colour);
|
|
}
|
|
|
|
struct text_params_t {
|
|
TextStyle style;
|
|
eTextMode mode;
|
|
bool showBreaks = false;
|
|
location offset = {0,0};
|
|
// Hilite ranges are, like the STL, of the form [first, last).
|
|
std::vector<hilite_t> hilite_ranges;
|
|
sf::Color hilite_fg, hilite_bg = sf::Color::Transparent;
|
|
enum {RECTS, SNIPPETS} returnType;
|
|
std::vector<RECT> returnRects;
|
|
std::vector<snippet_t> snippets;
|
|
};
|
|
|
|
void win_draw_string(sf::RenderTarget& dest_window,RECT dest_rect,std::string str,text_params_t& options);
|
|
|
|
void win_draw_string(sf::RenderTarget& dest_window,RECT dest_rect,std::string str,eTextMode mode,TextStyle style, location offset) {
|
|
text_params_t params;
|
|
params.mode = mode;
|
|
params.style = style;
|
|
params.offset = offset;
|
|
win_draw_string(dest_window, dest_rect, str, params);
|
|
}
|
|
|
|
std::vector<RECT> draw_string_hilite(sf::RenderTarget& dest_window,RECT dest_rect,std::string str,TextStyle style,std::vector<hilite_t> hilites,sf::Color hiliteClr) {
|
|
text_params_t params;
|
|
params.mode = eTextMode::WRAP;
|
|
params.hilite_ranges = hilites;
|
|
params.style = style;
|
|
params.hilite_fg = hiliteClr;
|
|
params.returnType = text_params_t::RECTS;
|
|
win_draw_string(dest_window, dest_rect, str, params);
|
|
return params.returnRects;
|
|
}
|
|
|
|
std::vector<snippet_t> draw_string_sel(sf::RenderTarget& dest_window,RECT dest_rect,std::string str,TextStyle style,std::vector<hilite_t> hilites,sf::Color hiliteClr) {
|
|
text_params_t params;
|
|
params.mode = eTextMode::WRAP;
|
|
params.showBreaks = true;
|
|
params.hilite_ranges = hilites;
|
|
params.style = style;
|
|
params.hilite_fg = style.colour;
|
|
params.hilite_bg = hiliteClr;
|
|
params.returnType = text_params_t::RECTS;
|
|
win_draw_string(dest_window, dest_rect, str, params);
|
|
return params.snippets;
|
|
}
|
|
|
|
static void push_snippets(size_t start, size_t end, text_params_t& options, size_t& iHilite, const std::string& str, location loc) {
|
|
std::vector<hilite_t>& hilites = options.hilite_ranges;
|
|
std::vector<snippet_t>& snippets = options.snippets;
|
|
// Check if we have any hilites on this line.
|
|
// We assume the list of hilites is sorted, so we just need to
|
|
// check the current entry.
|
|
size_t upper_bound = end;
|
|
do {
|
|
bool hilited = false;
|
|
// Skip any hilite rules that have start = end
|
|
while(iHilite < hilites.size() && hilites[iHilite].first == hilites[iHilite].second)
|
|
iHilite++;
|
|
if(iHilite < hilites.size()) {
|
|
// Possibilities: (vertical bars indicate line boundaries, parentheses for hilite boundaries, dots are data)
|
|
// 1. |...|...(...) --> no hilite on this line
|
|
// 2a. |...(...|...) --> hilite starts on this line and continues past it
|
|
// 2b. |...(...)...| --> hilite starts and ends on this line
|
|
// 3a. (...|...)...| --> hilite starts (or continues) at the start of the line and ends on this line
|
|
// 3b. (...|......)| --> entire line hilited
|
|
// Case 1 needs no special handling; check case 3, then case 2.
|
|
if(hilites[iHilite].first <= start) {
|
|
hilited = true;
|
|
if(hilites[iHilite].second < end) // 3a
|
|
end = hilites[iHilite].second;
|
|
} else if(hilites[iHilite].first < end)
|
|
end = hilites[iHilite].first;
|
|
// 2b will reduce to 3a after shifting start over
|
|
}
|
|
size_t amount = end - start;
|
|
snippets.push_back({str.substr(start,amount), loc, hilited});
|
|
loc.x += string_length(snippets[snippets.size()-1].text, options.style);
|
|
start = end;
|
|
end = upper_bound;
|
|
if(iHilite < hilites.size() && start >= hilites[iHilite].second)
|
|
iHilite++;
|
|
} while(start < upper_bound);
|
|
}
|
|
|
|
void win_draw_string(sf::RenderTarget& dest_window,RECT dest_rect,std::string str,text_params_t& options) {
|
|
if(str.empty()) return; // Nothing to do!
|
|
short line_height = options.style.lineHeight;
|
|
sf::Text str_to_draw;
|
|
options.style.applyTo(str_to_draw);
|
|
short str_len,i;
|
|
unsigned short last_line_break = 0,last_word_break = 0;
|
|
short total_width = 0;
|
|
short adjust_x = 0,adjust_y = 0;
|
|
|
|
adjust_x = options.offset.x;
|
|
adjust_y = options.offset.y;
|
|
str_to_draw.setString("fj"); // Something that has both an ascender and a descender
|
|
adjust_y -= str_to_draw.getLocalBounds().height;
|
|
|
|
str_to_draw.setString(str);
|
|
str_len = str.length();
|
|
if (str_len == 0) {
|
|
return;
|
|
}
|
|
|
|
eTextMode mode = options.mode;
|
|
total_width = str_to_draw.getLocalBounds().width;
|
|
if(mode == eTextMode::WRAP && total_width < dest_rect.width())
|
|
mode = eTextMode::LEFT_TOP;
|
|
if(mode == eTextMode::LEFT_TOP && str.find('|') != std::string::npos)
|
|
mode = eTextMode::WRAP;
|
|
|
|
auto text_len = [&str_to_draw](size_t i) -> int {
|
|
return str_to_draw.findCharacterPos(i).x;
|
|
};
|
|
|
|
// Special stuff
|
|
size_t iHilite = 0;
|
|
|
|
location moveTo;
|
|
line_height -= 2; // TODO: ...why are we arbitrarily reducing the line height from the requested value?
|
|
|
|
if(mode == eTextMode::WRAP) {
|
|
moveTo = location(dest_rect.left + 1 + adjust_x, dest_rect.top + 1 + 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.width() - 6))
|
|
&& (last_word_break > last_line_break)) || (str[i] == '|')) {
|
|
if(str[i] == '|') {
|
|
if(!options.showBreaks) str[i] = ' ';
|
|
last_word_break = i + 1;
|
|
}
|
|
push_snippets(last_line_break, last_word_break, options, iHilite, str, moveTo);
|
|
moveTo.y += line_height;
|
|
last_line_break = last_word_break;
|
|
}
|
|
if(str[i] == ' ')
|
|
last_word_break = i + 1;
|
|
}
|
|
|
|
if(i - last_line_break > 0) {
|
|
std::string snippet = str.substr(last_line_break);
|
|
if(!snippet.empty())
|
|
push_snippets(last_line_break, str.length() + 1, options, iHilite, str, moveTo);
|
|
}
|
|
} else {
|
|
switch(mode) {
|
|
case eTextMode::CENTRE:
|
|
moveTo = location((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);
|
|
break;
|
|
case eTextMode::LEFT_TOP:
|
|
moveTo = location(dest_rect.left + 1 + adjust_x, dest_rect.top + 1 + adjust_y + 9);
|
|
break;
|
|
case eTextMode::LEFT_BOTTOM:
|
|
moveTo = location(dest_rect.left + 1 + adjust_x, dest_rect.top + 1 + adjust_y + 9 + dest_rect.height() / 6);
|
|
break;
|
|
case eTextMode::WRAP:
|
|
break; // Never happens, but put this here to silence warning
|
|
}
|
|
push_snippets(0, str.length() + 1, options, iHilite, str, moveTo);
|
|
}
|
|
|
|
for(auto& snippet : options.snippets) {
|
|
str_to_draw.setString(snippet.text);
|
|
str_to_draw.setPosition(snippet.at);
|
|
if(snippet.hilited) {
|
|
RECT bounds = str_to_draw.getGlobalBounds();
|
|
// Adjust so that drawing the same text to
|
|
// the same rect is positioned exactly right
|
|
bounds.left = snippet.at.x - 1;
|
|
bounds.top = snippet.at.y + 5;
|
|
if(options.returnType == text_params_t::RECTS)
|
|
options.returnRects.push_back(bounds);
|
|
str_to_draw.setColor(options.hilite_fg);
|
|
bounds.inset(0,-4);
|
|
fill_rect(dest_window, bounds, options.hilite_bg);
|
|
} else str_to_draw.setColor(options.style.colour);
|
|
dest_window.draw(str_to_draw);
|
|
}
|
|
}
|
|
|
|
short string_length(std::string str, TextStyle style){
|
|
short total_width = 0;
|
|
|
|
sf::Text text;
|
|
style.applyTo(text);
|
|
text.setString(str);
|
|
total_width = text.getLocalBounds().width;
|
|
return total_width;
|
|
}
|
|
|
|
/*
|
|
void draw_terrain(){
|
|
short q,r,x,y,i,small_i;
|
|
location which_pt,where_draw;
|
|
RECT draw_rect,clipping_rect = {8,8,332,260};
|
|
unsigned char t_to_draw;
|
|
RECT source_rect,tiny_to,tiny_to_base = {37,29,44,36},tiny_from,from_rect,to_rect;
|
|
RECT boat_rect[4] = {{0,0,36,28}, {0,28,36,56},{0,56,36,84},{0,84,36,112}};
|
|
|
|
if (overall_mode >= 60)
|
|
return;
|
|
|
|
OffsetRect(&boat_rect[0],61,0);
|
|
|
|
if (cur_viewing_mode == 0) {
|
|
SetPort( ter_draw_gworld);
|
|
FillCRect(&terrain_rect,bg_rects[6]);
|
|
FrameRect(&terrain_rect);
|
|
SetPortWindowPort(mainPtr);
|
|
for (q = 0; q < 9; q++)
|
|
for (r = 0; r < 9; r++)
|
|
{
|
|
where_draw.x = q; where_draw.y = r;
|
|
if (editing_town == true) {
|
|
t_to_draw = t_d.terrain[cen_x + q - 4][cen_y + r - 4];
|
|
}
|
|
else {
|
|
if (cen_x + q - 4 == -1)
|
|
t_to_draw = borders[3][cen_y + r - 4];
|
|
else if (cen_x + q - 4 == 48)
|
|
t_to_draw = borders[1][cen_y + r - 4];
|
|
else if (cen_y + r - 4 == -1)
|
|
t_to_draw = borders[0][cen_x + q - 4];
|
|
else if (cen_y + r - 4 == 48)
|
|
t_to_draw = borders[2][cen_x + q - 4];
|
|
else t_to_draw = current_terrain.terrain[cen_x + q - 4][cen_y + r - 4];
|
|
}
|
|
draw_one_terrain_spot(q,r,t_to_draw);
|
|
which_pt.x = cen_x + q - 4;
|
|
which_pt.y =cen_y + r - 4;
|
|
|
|
tiny_to = tiny_to_base;
|
|
OffsetRect(&tiny_to,28 * q, 36 * r);
|
|
|
|
// draw start icon, if starting point
|
|
if ((editing_town == true) &&
|
|
(cur_town == scenario.which_town_start) && (scenario.where_start.x == cen_x + q - 4)
|
|
&& (scenario.where_start.y == cen_y + r - 4)) {
|
|
from_rect = start_button_from;
|
|
to_rect = tiny_to;
|
|
to_rect.left -= 14;
|
|
rect_draw_some_item(editor_mixed,from_rect,ter_draw_gworld,to_rect,0,0);
|
|
OffsetRect(&tiny_to,0,-7);
|
|
}
|
|
if ((editing_town == false)
|
|
&& (scenario.out_sec_start.x == cur_out.x)
|
|
&& (scenario.out_sec_start.y == cur_out.y)
|
|
&& (scenario.out_start.x == cen_x + q - 4)
|
|
&& (scenario.out_start.y == cen_y + r - 4)) {
|
|
from_rect = start_button_from;
|
|
to_rect = tiny_to;
|
|
to_rect.left -= 14;
|
|
rect_draw_some_item(editor_mixed,from_rect,ter_draw_gworld,to_rect,0,0);
|
|
OffsetRect(&tiny_to,0,-7);
|
|
}
|
|
small_i = small_icons[scenario.ter_types[t_to_draw].special];
|
|
if ((small_i == 30) && (scenario.ter_types[t_to_draw].flag2 >= 5))
|
|
small_i = 31;
|
|
if ((small_i == 31) && (scenario.ter_types[t_to_draw].flag2 == 10))
|
|
small_i = 32;
|
|
tiny_from = base_small_button_from;
|
|
OffsetRect(&tiny_from,7 * (small_i % 10),7 * (small_i / 10));
|
|
if (small_i > 0) {
|
|
rect_draw_some_item(editor_mixed,tiny_from,ter_draw_gworld,tiny_to,0,0);
|
|
OffsetRect(&tiny_to,0,-7);
|
|
}
|
|
|
|
if (is_special(cen_x + q - 4,cen_y + r - 4) == true) {
|
|
tiny_from = base_small_button_from;
|
|
OffsetRect(&tiny_from,7 * (7),7 * (0));
|
|
rect_draw_some_item(editor_mixed,tiny_from,ter_draw_gworld,tiny_to,0,0);
|
|
OffsetRect(&tiny_to,0,-7);
|
|
}
|
|
if ((t_to_draw == 7) || (t_to_draw == 10) || (t_to_draw == 13) || (t_to_draw == 16)) {
|
|
tiny_from = base_small_button_from;
|
|
OffsetRect(&tiny_from,7 * (3),7 * (2));
|
|
rect_draw_some_item(editor_mixed,tiny_from,ter_draw_gworld,tiny_to,0,0);
|
|
OffsetRect(&tiny_to,0,-7);
|
|
}
|
|
//if (is_s_d(cen_x + q - 4,cen_y + r - 4) == true) {
|
|
// }
|
|
if (editing_town == false) {
|
|
for (i = 0; i < 4; i++)
|
|
if ((cen_x + q - 4 == current_terrain.wandering_locs[i].x) &&
|
|
(cen_y + r - 4 == current_terrain.wandering_locs[i].y)) {
|
|
tiny_from = base_small_button_from;
|
|
OffsetRect(&tiny_from,7 * (2),7 * (1));
|
|
rect_draw_some_item(editor_mixed,tiny_from,ter_draw_gworld,tiny_to,0,0);
|
|
OffsetRect(&tiny_to,0,-7);
|
|
i = 4;
|
|
}
|
|
|
|
}
|
|
|
|
if (editing_town == true) {
|
|
for (i = 0; i < 30; i++) {
|
|
if ((scenario.scen_boats[i].which_town == cur_town) &&
|
|
(scenario.scen_boats[i].boat_loc.x == cen_x + q - 4) &&
|
|
(scenario.scen_boats[i].boat_loc.y == cen_y + r - 4))
|
|
Draw_Some_Item(mixed_gworld,boat_rect[0],ter_draw_gworld,where_draw,1,0);
|
|
|
|
}
|
|
for (i = 0; i < 30; i++) {
|
|
source_rect = boat_rect[0];
|
|
OffsetRect(&source_rect,0,74);
|
|
OffsetRect(&source_rect,56,36);
|
|
if ((scenario.scen_horses[i].which_town == cur_town) &&
|
|
(scenario.scen_horses[i].horse_loc.x == cen_x + q - 4) &&
|
|
(scenario.scen_horses[i].horse_loc.y == cen_y + r - 4))
|
|
Draw_Some_Item(mixed_gworld,source_rect,ter_draw_gworld,where_draw,1,0);
|
|
|
|
}
|
|
for (i = 0; i < 4; i++)
|
|
if ((cen_x + q - 4 == town.start_locs[i].x) &&
|
|
(cen_y + r - 4 == town.start_locs[i].y)) {
|
|
tiny_from = base_small_button_from;
|
|
OffsetRect(&tiny_from,7 * (6 + i),7 * (1));
|
|
rect_draw_some_item(editor_mixed,tiny_from,ter_draw_gworld,tiny_to,0,0);
|
|
OffsetRect(&tiny_to,0,-7);
|
|
}
|
|
for (i = 0; i < 4; i++)
|
|
if ((cen_x + q - 4 == town.wandering_locs[i].x) &&
|
|
(cen_y + r - 4 == town.wandering_locs[i].y)) {
|
|
tiny_from = base_small_button_from;
|
|
OffsetRect(&tiny_from,7 * (2),7 * (1));
|
|
rect_draw_some_item(editor_mixed,tiny_from,ter_draw_gworld,tiny_to,0,0);
|
|
OffsetRect(&tiny_to,0,-7);
|
|
i = 4;
|
|
}
|
|
if (is_web(cen_x + q - 4,cen_y + r - 4) == true) {
|
|
from_rect = calc_rect(5,0);
|
|
Draw_Some_Item(field_gworld,from_rect,ter_draw_gworld,where_draw,1,0);
|
|
}
|
|
if (is_crate(cen_x + q - 4,cen_y + r - 4) == true) {
|
|
from_rect = calc_rect(6,0);
|
|
Draw_Some_Item(field_gworld,from_rect,ter_draw_gworld,where_draw,1,0);
|
|
}
|
|
if (is_barrel(cen_x + q - 4,cen_y + r - 4) == true) {
|
|
from_rect = calc_rect(7,0);
|
|
Draw_Some_Item(field_gworld,from_rect,ter_draw_gworld,where_draw,1,0);
|
|
}
|
|
if (is_fire_barrier(cen_x + q - 4,cen_y + r - 4) == true) {
|
|
from_rect = calc_rect(0,2);
|
|
Draw_Some_Item(field_gworld,from_rect,ter_draw_gworld,where_draw,1,0);
|
|
}
|
|
if (is_quickfire(cen_x + q - 4,cen_y + r - 4) == true) {
|
|
from_rect = calc_rect(7,1);
|
|
Draw_Some_Item(field_gworld,from_rect,ter_draw_gworld,where_draw,1,0);
|
|
}
|
|
if (is_force_barrier(cen_x + q - 4,cen_y + r - 4) == true) {
|
|
from_rect = calc_rect(2,2);
|
|
Draw_Some_Item(field_gworld,from_rect,ter_draw_gworld,where_draw,1,0);
|
|
}
|
|
for (i = 0; i < 8; i++)
|
|
if (is_sfx(cen_x + q - 4,cen_y + r - 4,i)) {
|
|
from_rect = calc_rect(i,3);
|
|
Draw_Some_Item(field_gworld,from_rect,ter_draw_gworld,where_draw,1,0);
|
|
}
|
|
for (x = 0; x < 64; x++)
|
|
if ((cen_x + q - 4 == town.preset_items[x].item_loc.x) &&
|
|
(cen_y + r - 4 == town.preset_items[x].item_loc.y) && (town.preset_items[x].item_code >= 0)) {
|
|
}
|
|
for (x = 0; x < 60; x++)
|
|
if ((cen_x + q - 4 == t_d.creatures[x].start_loc.x) &&
|
|
(cen_y + r - 4 == t_d.creatures[x].start_loc.y) && (t_d.creatures[x].number != 0)) {
|
|
}
|
|
|
|
}
|
|
}
|
|
if (editing_town == true) {
|
|
draw_monsts();
|
|
draw_items();
|
|
}
|
|
|
|
SetPort( ter_draw_gworld);
|
|
ClipRect(&clipping_rect);
|
|
|
|
if (editing_town == true) {
|
|
// draw info rects
|
|
for (i = 0; i < 16; i++)
|
|
if (t_d.room_rect[i].left > 0) {
|
|
draw_rect.left = 22 + 28 * (t_d.room_rect[i].left - cen_x + 4);
|
|
draw_rect.right = 22 + 28 * (t_d.room_rect[i].right - cen_x + 4);
|
|
draw_rect.top = 24 + 36 * (t_d.room_rect[i].top - cen_y + 4);
|
|
draw_rect.bottom = 24 + 36 * (t_d.room_rect[i].bottom - cen_y + 4);
|
|
ForeColor(redColor);
|
|
FrameRect(&draw_rect);
|
|
ForeColor(blackColor);
|
|
}
|
|
// draw border rect
|
|
draw_rect.left = 21 + 28 * (town.in_town_rect.left - cen_x + 4);
|
|
draw_rect.right = 21 + 28 * (town.in_town_rect.right - cen_x + 4);
|
|
draw_rect.top = 25 + 36 * (town.in_town_rect.top - cen_y + 4);
|
|
draw_rect.bottom = 25 + 36 * (town.in_town_rect.bottom - cen_y + 4);
|
|
ForeColor(whiteColor);
|
|
FrameRect(&draw_rect);
|
|
ForeColor(blackColor);
|
|
}
|
|
if (editing_town == false) {
|
|
// draw info rects
|
|
for (i = 0; i < 8; i++)
|
|
if (current_terrain.info_rect[i].left > 0) {
|
|
draw_rect.left = 22 + 28 * (current_terrain.info_rect[i].left - cen_x + 4);
|
|
draw_rect.right = 22 + 28 * (current_terrain.info_rect[i].right - cen_x + 4);
|
|
draw_rect.top = 24 + 36 * (current_terrain.info_rect[i].top - cen_y + 4);
|
|
draw_rect.bottom = 24 + 36 * (current_terrain.info_rect[i].bottom - cen_y + 4);
|
|
ForeColor(redColor);
|
|
FrameRect(&draw_rect);
|
|
ForeColor(blackColor);
|
|
}
|
|
}
|
|
ClipRect(&terrain_rect);
|
|
SetPortWindowPort(mainPtr);
|
|
|
|
small_any_drawn = false;
|
|
//if (cur_viewing_mode == 0)
|
|
// draw_frames();
|
|
}
|
|
|
|
if (cur_viewing_mode == 1) {
|
|
SetPort( ter_draw_gworld);
|
|
if (small_any_drawn == false) {
|
|
FillCRect(&terrain_rect,bg_rects[6]);
|
|
FrameRect(&terrain_rect);
|
|
}
|
|
for (q = 0; q < ((editing_town == true) ? max_dim[town_type] : 48); q++)
|
|
for (r = 0; r < ((editing_town == true) ? max_dim[town_type] : 48); r++) {
|
|
t_to_draw = (editing_town == true) ? t_d.terrain[q][r] :
|
|
current_terrain.terrain[q][r];
|
|
if ((small_what_drawn[q][r] != t_to_draw) || (small_any_drawn == false)) {
|
|
draw_one_tiny_terrain_spot(q,r,t_to_draw);
|
|
small_what_drawn[q][r] = t_to_draw;
|
|
}
|
|
}
|
|
SetPortWindowPort(mainPtr);
|
|
small_any_drawn = true;
|
|
}
|
|
|
|
//draw_cur_string();
|
|
place_location();
|
|
|
|
//to_rect = world_screen;
|
|
//OffsetRect(&to_rect,TER_RECT_UL_X,TER_RECT_UL_Y);
|
|
rect_draw_some_item(ter_draw_gworld,terrain_rect,ter_draw_gworld,world_screen,0,1);
|
|
}*/
|
|
|
|
RECT calc_rect(short i, short j){
|
|
RECT base_rect = {0,0,36,28};
|
|
|
|
base_rect.offset(i * 28, j * 36);
|
|
return base_rect;
|
|
}
|
|
|
|
graf_pos cCustomGraphics::find_graphic(pic_num_t which_rect, bool party) {
|
|
short sheet = which_rect / 100;
|
|
if(is_old) sheet = 0;
|
|
else which_rect %= 100;
|
|
RECT store_rect = {0,0,36,28};
|
|
|
|
store_rect.offset(28 * (which_rect % 10),36 * (which_rect / 10));
|
|
return std::make_pair(party ? this->party : &sheets[sheet],store_rect);
|
|
}
|
|
|
|
size_t cCustomGraphics::count() {
|
|
if(sheets == NULL) return 0;
|
|
else if(is_old) {
|
|
RECT bounds(sheets[0]);
|
|
if(bounds.width() < 280) return bounds.width() / 28;
|
|
return bounds.height() / 36;
|
|
} else {
|
|
size_t count = 100 * (numSheets - 1);
|
|
RECT bounds(sheets[numSheets - 1]);
|
|
if(bounds.width() < 280) count += bounds.width() / 28;
|
|
else count += bounds.height() / 36;
|
|
return count;
|
|
}
|
|
}
|
|
|
|
// TODO: This doesn't belong in this file
|
|
std::string get_str(std::string list, short j){
|
|
if(j == 0) return list;
|
|
StringRsrc& strings = *ResMgr::get<StringRsrc>(list);
|
|
return strings[j - 1];
|
|
}
|
|
|
|
m_pic_index_t m_pic_index[] = {
|
|
{1, 1, 1},
|
|
{2, 1, 1},
|
|
{3, 1, 1},
|
|
{4, 1, 1},
|
|
{5, 1, 1},
|
|
{6, 1, 1},
|
|
{7, 1, 1},
|
|
{8, 1, 1},
|
|
{9, 1, 1},
|
|
{10, 1, 1},
|
|
//10
|
|
{11, 1, 1},
|
|
{12, 1, 1},
|
|
{13, 1, 1},
|
|
{14, 1, 1},
|
|
{15, 1, 1},
|
|
{16, 1, 1},
|
|
{17, 1, 1},
|
|
{18, 1, 1},
|
|
{19, 1, 1},
|
|
{20, 1, 1},
|
|
//20
|
|
{21, 1, 1},
|
|
{22, 1, 1},
|
|
{23, 1, 1},
|
|
{24, 1, 1},
|
|
{25, 1, 1},
|
|
{26, 1, 1},
|
|
{27, 1, 1},
|
|
{28, 1, 1},
|
|
{29, 1, 1},
|
|
{30, 1, 1},
|
|
//30
|
|
{31, 1, 1},
|
|
{32, 1, 1},
|
|
{33, 1, 1},
|
|
{34, 1, 1},
|
|
{35, 1, 1},
|
|
{36, 1, 1},
|
|
{37, 1, 1},
|
|
{38, 1, 1},
|
|
{39, 1, 1},
|
|
{40, 1, 1},
|
|
//40
|
|
{41, 1, 1},
|
|
{42, 1, 1},
|
|
{43, 1, 1},
|
|
{44, 1, 1},
|
|
{46, 1, 1},
|
|
{47, 1, 1},
|
|
{48, 1, 1},
|
|
{49, 1, 1},
|
|
{50, 1, 1},
|
|
{51, 1, 2},
|
|
//50
|
|
{53, 1, 2},
|
|
{55, 1, 2},
|
|
{57, 1, 2},
|
|
{59, 1, 1},
|
|
{60, 1, 1},
|
|
{61, 1, 1},
|
|
{62, 1, 1},
|
|
{63, 1, 1},
|
|
{64, 1, 1},
|
|
{65, 1, 1},
|
|
//60
|
|
{66, 1, 1},
|
|
{67, 1, 1},
|
|
{68, 1, 1},
|
|
{69, 1, 1},
|
|
{70, 1, 1},
|
|
{71, 1, 1},
|
|
{72, 1, 1},
|
|
{73, 1, 1},
|
|
{74, 1, 1},
|
|
{75, 1, 1},
|
|
//70
|
|
{76, 1, 1},
|
|
{77, 1, 1},
|
|
{78, 1, 1},
|
|
{79, 2, 1},
|
|
{81, 1, 1},
|
|
{82, 1, 1},
|
|
{83, 1, 2},
|
|
{85, 1, 1},
|
|
{86, 1, 1},
|
|
{87, 1, 1},
|
|
//80
|
|
{88, 1, 1},
|
|
{89, 1, 1},
|
|
{90, 1, 1},
|
|
{91, 1, 1},
|
|
{92, 1, 1},
|
|
{93, 1, 1},
|
|
{94, 1, 1},
|
|
{95, 1, 1},
|
|
{96, 1, 1},
|
|
{97, 1, 1},
|
|
//90
|
|
{98, 1, 1},
|
|
{99, 1, 1},
|
|
{100, 1, 1},
|
|
{101, 1, 1},
|
|
{102, 1, 1},
|
|
{103, 1, 1},
|
|
{104, 1, 1},
|
|
{105, 1, 1},
|
|
{106, 1, 1},
|
|
{107, 1, 1},
|
|
//100
|
|
{108, 1, 1},
|
|
{109, 2, 1},
|
|
{111, 1, 1},
|
|
{112, 1, 1},
|
|
{113, 1, 1},
|
|
{114, 2, 1},
|
|
{116, 1, 1},
|
|
{117, 1, 1},
|
|
{118, 1, 1},
|
|
{119, 1, 1},
|
|
//110
|
|
{120, 2, 1},
|
|
{122, 1, 1},
|
|
{123, 1, 2},
|
|
{125, 1, 2},
|
|
{127, 1, 1},
|
|
{128, 1, 1},
|
|
{129, 1, 1},
|
|
{130, 1, 1},
|
|
{131, 2, 2},
|
|
{135, 1, 1},
|
|
//120
|
|
{136, 1, 1},
|
|
{137, 2, 1},
|
|
{139, 1, 1},
|
|
{140, 1, 1},
|
|
{141, 1, 1},
|
|
{142, 1, 1},
|
|
{143, 1, 1},
|
|
{144, 1, 1},
|
|
{145, 1, 1},
|
|
{146, 1, 1},
|
|
//130
|
|
{147, 1, 1},
|
|
{148, 1, 1},
|
|
{149, 1, 1},
|
|
{150, 1, 1},
|
|
{151, 1, 1},
|
|
{152, 1, 1},
|
|
{153, 1, 1},
|
|
{154, 1, 1},
|
|
{155, 2, 2},
|
|
{159, 1, 1},
|
|
//140
|
|
{160, 2, 2},
|
|
{164, 2, 1},
|
|
{166, 2, 1},
|
|
{168, 1, 2},
|
|
{170, 1, 1},
|
|
{171, 1, 1},
|
|
{172, 1, 1},
|
|
{173, 1, 1},
|
|
{174, 1, 1},
|
|
{175, 1, 1},
|
|
//150
|
|
{176, 1, 1},
|
|
{177, 1, 1},
|
|
{178, 1, 1},
|
|
{179, 1, 1},
|
|
{180, 1, 1},
|
|
{181, 1, 1},
|
|
{182, 1, 1},
|
|
{183, 1, 1},
|
|
{184, 1, 1},
|
|
{185, 1, 1},
|
|
//160
|
|
{186, 1, 1},
|
|
{187, 1, 1},
|
|
{188, 1, 1},
|
|
{189, 1, 1},
|
|
{190, 1, 1},
|
|
{191, 1, 1},
|
|
{192, 1, 1},
|
|
{193, 1, 1},
|
|
{194, 1, 1},
|
|
{195, 1, 1},
|
|
//170
|
|
{196, 1, 1},
|
|
{197, 1, 1},
|
|
{198, 1, 1},
|
|
{0, 1, 1},
|
|
{45, 1, 1},
|
|
{199, 1, 1},
|
|
{200, 1, 1},
|
|
{201, 1, 1},
|
|
{202, 1, 1},
|
|
{203, 1, 1},
|
|
//180
|
|
{204, 1, 1},
|
|
{0, 1, 1},
|
|
{0, 1, 1},
|
|
{0, 1, 1},
|
|
{0, 1, 1},
|
|
{0, 1, 1},
|
|
{0, 1, 1},
|
|
{0, 1, 1},
|
|
{0, 1, 1},
|
|
{0, 1, 1},
|
|
//190
|
|
{0, 1, 1},
|
|
{0, 1, 1},
|
|
{0, 1, 1},
|
|
{0, 1, 1},
|
|
{0, 1, 1},
|
|
{0, 1, 1},
|
|
{0, 1, 1},
|
|
{0, 1, 1},
|
|
{0, 1, 1},
|
|
{0, 1, 1},
|
|
//200
|
|
};
|
|
|
|
// TODO: Put these classes in a header?
|
|
class Ellipse : public sf::Shape {
|
|
float divSz;
|
|
int points;
|
|
float a, b;
|
|
public:
|
|
explicit Ellipse(sf::Vector2f size, unsigned int points = 30) : points(points) {
|
|
a = size.x / 2.0f;
|
|
b = size.y / 2.0f;
|
|
divSz = 2 * pi<float>() / points;
|
|
update();
|
|
}
|
|
|
|
unsigned int getPointCount() const override {
|
|
return points;
|
|
}
|
|
|
|
sf::Vector2f getPoint(unsigned int i) const override {
|
|
float t = i * divSz;
|
|
return sf::Vector2f(a + a*sin(t), b + b*cos(t));
|
|
}
|
|
|
|
// TODO: Additional functions?
|
|
};
|
|
|
|
class RoundRect : public sf::Shape {
|
|
float divSz;
|
|
int points;
|
|
float w,h,r;
|
|
public:
|
|
RoundRect(sf::Vector2f size, float cornerRadius, unsigned int points = 32) : points(points / 4) {
|
|
w = size.x;
|
|
h = size.y;
|
|
r = cornerRadius;
|
|
divSz = 2 * pi<float>() / points;
|
|
update();
|
|
}
|
|
|
|
unsigned int getPointCount() const override {
|
|
return points * 4;
|
|
}
|
|
|
|
sf::Vector2f getPoint(unsigned int i) const override {
|
|
const float pi = ::pi<float>();
|
|
const float half_pi = 0.5 * pi;
|
|
float t = i * divSz;
|
|
switch(i / points) {
|
|
case 0: // top left corner
|
|
return {r + r*sin(t + pi), r + r*cos(t + pi)};
|
|
case 1: // bottom left corner
|
|
return {r + r*cos(t + half_pi), h - r + r*sin(t - half_pi)};
|
|
case 2: // bottom right corner
|
|
return {w - r + r*cos(t + half_pi), h - r - r*sin(t + half_pi)};
|
|
case 3: // top right corner
|
|
return {w - r - r*cos(t - half_pi), r + r*sin(t - half_pi)};
|
|
}
|
|
// Unreachable
|
|
printf("Whoops, rounded rectangle had bad point!");
|
|
return {0,0};
|
|
}
|
|
|
|
// TODO: Additional functions?
|
|
};
|
|
|
|
void draw_line(sf::RenderTarget& target, location from, location to, int thickness, sf::Color colour, sf::BlendMode mode) {
|
|
sf::VertexArray line(sf::LinesStrip, 2);
|
|
line[0].position = from;
|
|
line[0].color = colour;
|
|
line[1].position = to;
|
|
line[1].color = colour;
|
|
setActiveRenderTarget(target);
|
|
float saveThickness;
|
|
glGetFloatv(GL_LINE_WIDTH, &saveThickness);
|
|
glLineWidth(thickness);
|
|
target.draw(line, mode);
|
|
glLineWidth(saveThickness);
|
|
}
|
|
|
|
static void fill_shape(sf::RenderTarget& target, sf::Shape& shape, int x, int y, sf::Color colour) {
|
|
shape.setPosition(x, y);
|
|
shape.setFillColor(colour);
|
|
setActiveRenderTarget(target);
|
|
target.draw(shape);
|
|
|
|
}
|
|
|
|
static void frame_shape(sf::RenderTarget& target, sf::Shape& shape, int x, int y, sf::Color colour) {
|
|
shape.setPosition(x, y);
|
|
shape.setOutlineColor(colour);
|
|
shape.setFillColor(sf::Color::Transparent);
|
|
// TODO: Determine the correct outline value; should be one pixel, not sure if it should be negative
|
|
shape.setOutlineThickness(1.0);
|
|
target.draw(shape);
|
|
}
|
|
|
|
void fill_rect(sf::RenderTarget& target, RECT rect, sf::Color colour) {
|
|
sf::RectangleShape fill(sf::Vector2f(rect.width(), rect.height()));
|
|
fill_shape(target, fill, rect.left, rect.top, colour);
|
|
}
|
|
|
|
void frame_rect(sf::RenderTarget& target, RECT rect, sf::Color colour) {
|
|
sf::RectangleShape frame(sf::Vector2f(rect.width(), rect.height()));
|
|
frame_shape(target, frame, rect.left, rect.top, colour);
|
|
}
|
|
|
|
void fill_roundrect(sf::RenderTarget& target, RECT rect, int rad, sf::Color colour) {
|
|
RoundRect fill(sf::Vector2f(rect.width(), rect.height()), rad);
|
|
fill_shape(target, fill, rect.left, rect.top, colour);
|
|
}
|
|
|
|
void frame_roundrect(sf::RenderTarget& target, RECT rect, int rad, sf::Color colour) {
|
|
RoundRect frame(sf::Vector2f(rect.width(), rect.height()), rad);
|
|
frame_shape(target, frame, rect.left, rect.top, colour);
|
|
}
|
|
|
|
void fill_circle(sf::RenderTarget& target, RECT rect, sf::Color colour) {
|
|
Ellipse fill(sf::Vector2f(rect.width(), rect.height()));
|
|
fill_shape(target, fill, rect.left, rect.top, colour);
|
|
}
|
|
|
|
void frame_circle(sf::RenderTarget& target, RECT rect, sf::Color colour) {
|
|
Ellipse frame(sf::Vector2f(rect.width(), rect.height()));
|
|
frame_shape(target, frame, rect.left, rect.top, colour);
|
|
}
|
|
|
|
void fill_region(sf::RenderWindow& target, Region& region, sf::Color colour) {
|
|
clip_region(target, region);
|
|
fill_rect(target, RECT(target), colour);
|
|
undo_clip(target);
|
|
}
|
|
|
|
void frame_region(sf::RenderWindow& target, Region& region, sf::Color colour) {
|
|
// TODO: Uh, actually, this won't do what it says. Eh, I'll fix it if I ever use it.
|
|
clip_region(target, region);
|
|
frame_rect(target, RECT(target), colour);
|
|
undo_clip(target);
|
|
}
|
|
|
|
void Region::addEllipse(RECT frame) {
|
|
Ellipse* ellipse = new Ellipse(sf::Vector2f(frame.width(), frame.height()));
|
|
ellipse->setFillColor(sf::Color::Black);
|
|
shapes.push_back(std::shared_ptr<sf::Shape>(ellipse));
|
|
}
|
|
|
|
void Region::addRect(RECT rect){
|
|
sf::RectangleShape* frame = new sf::RectangleShape(sf::Vector2f(rect.width(), rect.height()));
|
|
frame->setPosition(rect.left, rect.top);
|
|
frame->setFillColor(sf::Color::Black);
|
|
shapes.push_back(std::shared_ptr<sf::Shape>(frame));
|
|
}
|
|
|
|
void Region::clear() {
|
|
shapes.clear();
|
|
}
|
|
|
|
void Region::offset(int x, int y) {
|
|
for(auto shape : shapes) {
|
|
shape->move(x,y);
|
|
}
|
|
}
|
|
|
|
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
|
|
void Region::setStencil(sf::RenderWindow& where) {
|
|
where.setActive();
|
|
glClearStencil(0);
|
|
glClear(GL_STENCIL_BUFFER_BIT);
|
|
glEnable(GL_STENCIL_TEST);
|
|
glStencilFunc(GL_ALWAYS, 1, 1);
|
|
for(auto shape : shapes) {
|
|
// Save the colour in case we need to reuse this region
|
|
sf::Color colour = shape->getFillColor();
|
|
if(colour == sf::Color::Black)
|
|
glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
|
|
else glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
|
|
// Make transparent so we don't overwrite important stuff
|
|
shape->setFillColor(sf::Color::Transparent);
|
|
where.draw(*shape);
|
|
shape->setFillColor(colour);
|
|
}
|
|
glStencilFunc(GL_EQUAL, 1, 1);
|
|
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
|
}
|
|
|
|
void clip_rect(sf::RenderTarget& where, RECT rect) {
|
|
rect |= RECT(where); // Make sure we don't draw out of bounds
|
|
// TODO: Make sure this works for the scissor test...
|
|
setActiveRenderTarget(where);
|
|
glEnable(GL_SCISSOR_TEST);
|
|
glScissor(rect.left, RECT(where).height() - rect.bottom, rect.width(), rect.height());
|
|
}
|
|
|
|
void clip_region(sf::RenderWindow& where, Region& region) {
|
|
region.setStencil(where);
|
|
}
|
|
|
|
void undo_clip(sf::RenderTarget& where) {
|
|
setActiveRenderTarget(where);
|
|
glDisable(GL_SCISSOR_TEST);
|
|
glDisable(GL_STENCIL_TEST);
|
|
}
|
|
|
|
void setActiveRenderTarget(sf::RenderTarget& where) {
|
|
const std::type_info& type = typeid(where);
|
|
if(type == typeid(sf::RenderWindow&))
|
|
dynamic_cast<sf::RenderWindow&>(where).setActive();
|
|
else if(type == typeid(sf::RenderTexture&))
|
|
dynamic_cast<sf::RenderTexture&>(where).setActive();
|
|
else throw std::bad_cast();
|
|
}
|
|
|
|
Region& Region::operator-=(Region& other) {
|
|
for(auto shape : other.shapes) {
|
|
// TODO: Shouldn't this be done to a copy of the shape instead?
|
|
if(shape->getFillColor() == sf::Color::Black)
|
|
shape->setFillColor(sf::Color::White);
|
|
else shape->setFillColor(sf::Color::Black);
|
|
shapes.push_back(shape);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
struct tessel_t {
|
|
sf::RenderTexture* tessel;
|
|
sf::Texture* img;
|
|
RECT srcRect;
|
|
};
|
|
|
|
bool operator==(const tessel_ref_t& a, const tessel_ref_t& b) {
|
|
return a.key == b.key;
|
|
}
|
|
|
|
template<> struct std::hash<tessel_ref_t> {
|
|
size_t operator()(tessel_ref_t key) const {
|
|
return key.key;
|
|
}
|
|
};
|
|
|
|
std::unordered_map<tessel_ref_t, tessel_t> 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;
|
|
}
|
|
|
|
void flushTessels(sf::Texture& alteredImg) {
|
|
erase_if(tiling_reservoir, [&alteredImg](std::pair<const tessel_ref_t,tessel_t>& 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]);
|
|
}
|
|
}
|
|
|
|
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<Texture*,rectangle>.
|
|
// 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<short(short,short)> get_obscurity) {
|
|
short storage = 0;
|
|
|
|
if(p1.y == p2.y) {
|
|
if(p1.x > p2.x) {
|
|
for(short count = p2.x + 1; count < p1.x; count++)
|
|
storage += get_obscurity(count, p1.y);
|
|
} else {
|
|
for(short count = p1.x + 1; count < p2.x; count++)
|
|
storage += get_obscurity(count, p1.y);
|
|
}
|
|
} else if(p1.x == p2.x) {
|
|
if(p1.y > p2.y) {
|
|
for(short count = p1.y - 1; count > p2.y; count--)
|
|
storage += get_obscurity(p1.x, count);
|
|
} else {
|
|
for(short count = p1.y + 1; count < p2.y; count++)
|
|
storage += get_obscurity(p1.x, count);
|
|
}
|
|
} else {
|
|
short dx = p2.x - p1.x;
|
|
short dy = p2.y - p1.y;
|
|
|
|
if(abs(dy) > abs(dx)) {
|
|
if(p2.y > p1.y) {
|
|
for(short count = 1; count < dy; count++)
|
|
storage += get_obscurity(p1.x + (count * dx) / dy, p1.y + count);
|
|
} else {
|
|
for(short count = -1; count > dy; count--)
|
|
storage += get_obscurity(p1.x + (count * dx) / dy, p1.y + count);
|
|
}
|
|
}
|
|
if(abs(dy) <= abs(dx)) {
|
|
if(p2.x > p1.x) {
|
|
for(short count = 1; count < dx; count++)
|
|
storage += get_obscurity(p1.x + count, p1.y + (count * dy) / dx);
|
|
} else {
|
|
for(short count = -1; count > dx; count--)
|
|
storage += get_obscurity(p1.x + count, p1.y + (count * dy) / dx);
|
|
}
|
|
}
|
|
}
|
|
return storage;
|
|
}
|