mirror of
https://gitlab.com/manzerbredes/ochess.git
synced 2025-04-07 02:26:29 +02:00
Debug animations, LiveEngine and improve arrow/squares highlights
This commit is contained in:
parent
179a173b3b
commit
e069a29f99
7 changed files with 95 additions and 94 deletions
2
TODO.md
2
TODO.md
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
## Before releasing v0.1.0
|
## Before releasing v0.1.0
|
||||||
- [ ] Implement pawn promotions in BoardCanvas
|
- [ ] Implement pawn promotions in BoardCanvas
|
||||||
- [ ] Debug animations (have a more reliable approach (can segfault when clicking on variations in the editor))
|
- [x] Debug animations (have a more reliable approach (can segfault when clicking on variations in the editor))
|
||||||
- [x] In BoardCanvas search for a workaround of the dynamic allocation of adata.buffer (on canvas resize)
|
- [x] In BoardCanvas search for a workaround of the dynamic allocation of adata.buffer (on canvas resize)
|
||||||
- [x] Bind the chess game editor settings to EditorPrefs.hpp
|
- [x] Bind the chess game editor settings to EditorPrefs.hpp
|
||||||
- [x] Ask before closing MainWindow/Tabs if anything is not saved
|
- [x] Ask before closing MainWindow/Tabs if anything is not saved
|
||||||
|
|
|
@ -59,8 +59,8 @@ MainWindow::MainWindow()
|
||||||
|
|
||||||
|
|
||||||
// Temporary TO REMOVE JUST FOR TESTS:
|
// Temporary TO REMOVE JUST FOR TESTS:
|
||||||
/*BaseTab *bt = new BaseTab((wxFrame *)notebook, "/home/loic/pgn/wijk_2003_annotated.pgn");
|
//BaseTab *bt = new BaseTab((wxFrame *)notebook, "/home/loic/pgn/wijk_2003_annotated.pgn");
|
||||||
this->AddPage(bt,bt);*/
|
//this->AddPage(bt,bt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::OnAuiNotebookPageCheck(wxAuiNotebookEvent& event){
|
void MainWindow::OnAuiNotebookPageCheck(wxAuiNotebookEvent& event){
|
||||||
|
|
|
@ -72,14 +72,15 @@ void GameTabLeftPanel::OnPlay(wxCommandEvent &event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameTabLeftPanel::SetEngineArrows(std::vector<std::string> arrows){
|
void GameTabLeftPanel::SetEngineArrows(std::vector<std::string> arrows){
|
||||||
engine_arrows=arrows;
|
engine_arrows.clear();
|
||||||
int min_size=5, max_size=80;
|
float scale=1;
|
||||||
int steps=(max_size-min_size)/arrows.size();
|
unsigned char color=0;
|
||||||
int current_size=max_size;
|
for(auto const &arrow:arrows){
|
||||||
for(std::string &arrow:engine_arrows){
|
std::string src=arrow.substr(0,2);
|
||||||
wxLogDebug("%s",arrow);
|
std::string dst=arrow.substr(2,2);
|
||||||
arrow+="#000000%"+std::to_string(current_size);
|
engine_arrows.push_back({src,dst,wxColour(color,color,color),scale});
|
||||||
current_size-=steps;
|
scale=std::max(0.1,scale-0.25);
|
||||||
|
color=std::min(255,color+70);
|
||||||
}
|
}
|
||||||
Notify(true);
|
Notify(true);
|
||||||
}
|
}
|
||||||
|
@ -94,16 +95,14 @@ void GameTabLeftPanel::Notify(bool skip_animation) {
|
||||||
// Update capture and check if we should to animations during moves change:
|
// Update capture and check if we should to animations during moves change:
|
||||||
if (m){
|
if (m){
|
||||||
captures = m->GetLineCaptures();
|
captures = m->GetLineCaptures();
|
||||||
if(!m->IsVariation()){ // Animations can lead to segfault when clicking on CGEditor move
|
if(m->HasParent(last_move) && !m->IsVariation()){
|
||||||
if(m->HasParent(last_move)){
|
m->GetAbsoluteMove(src,dst);
|
||||||
m->GetAbsoluteMove(src,dst);
|
animate=true;
|
||||||
animate=true;
|
}else if(m->HasChild(last_move) && !last_move->IsVariation()){ // call to IsVariation is safe because of HasChild() before! cf below
|
||||||
}else if(m->HasChild(last_move)){
|
// Accessing last_move here is safe since it is still
|
||||||
// Accessing last_move here is safe since it is still
|
// in the tree of moves (since HasChild found it so not deleted)
|
||||||
// in the tree of moves (since HasChild found it so not deleted)
|
last_move->GetAbsoluteMove(dst,src);
|
||||||
last_move->GetAbsoluteMove(dst,src);
|
animate=true;
|
||||||
animate=true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if(game->GetNextMove()){ // First move animation
|
} else if(game->GetNextMove()){ // First move animation
|
||||||
HalfMove *next=game->GetNextMove();
|
HalfMove *next=game->GetNextMove();
|
||||||
|
@ -128,8 +127,8 @@ void GameTabLeftPanel::Notify(bool skip_animation) {
|
||||||
std::string src_hl, dst_hl;
|
std::string src_hl, dst_hl;
|
||||||
m->GetAbsoluteMove(src_hl,dst_hl);
|
m->GetAbsoluteMove(src_hl,dst_hl);
|
||||||
if(src_hl.size()>0){ // Just in case
|
if(src_hl.size()>0){ // Just in case
|
||||||
gs.squares_hl.push_back(src_hl+"d");
|
gs.squares_hl.push_back({src_hl,wxColour(255,190,190)});
|
||||||
gs.squares_hl.push_back(dst_hl+"a");
|
gs.squares_hl.push_back({dst_hl,wxColour(255,100,100)});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(skip_animation || !animate){
|
if(skip_animation || !animate){
|
||||||
|
|
|
@ -13,7 +13,7 @@ class GameTabLeftPanel : public TabGameLeftPanel {
|
||||||
BoardCanvas *board_canvas;
|
BoardCanvas *board_canvas;
|
||||||
bool repeat;
|
bool repeat;
|
||||||
HalfMove *last_move;
|
HalfMove *last_move;
|
||||||
std::vector<std::string> engine_arrows;
|
std::vector<GameState::Arrow> engine_arrows;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GameTabLeftPanel(wxFrame *parent, std::shared_ptr<Game> game);
|
GameTabLeftPanel(wxFrame *parent, std::shared_ptr<Game> game);
|
||||||
|
|
|
@ -18,9 +18,10 @@ BoardCanvas::BoardCanvas(wxFrame *parent)
|
||||||
valid_drag = false;
|
valid_drag = false;
|
||||||
arrow_drag = false;
|
arrow_drag = false;
|
||||||
arrows_offset = t->GetSquaresSizes()/2.5;
|
arrows_offset = t->GetSquaresSizes()/2.5;
|
||||||
|
arrow_thickness = t->GetSquaresSizes()/1.8;
|
||||||
// Init animation data
|
// Init animation data
|
||||||
adata.duration=100;
|
adata.duration=100;
|
||||||
adata.duration_fast=100;
|
adata.duration_fast=50;
|
||||||
adata.fps=60;
|
adata.fps=60;
|
||||||
adata.buffer=new wxBitmap(500,500,32);
|
adata.buffer=new wxBitmap(500,500,32);
|
||||||
adata.animate=false;
|
adata.animate=false;
|
||||||
|
@ -230,30 +231,19 @@ void BoardCanvas::DrawBoard(wxDC &dc) {
|
||||||
|
|
||||||
// Draw highlighted squares
|
// Draw highlighted squares
|
||||||
for(int i=0;i<(gs.squares_hl.size()+squares_hl.size());i++){
|
for(int i=0;i<(gs.squares_hl.size()+squares_hl.size());i++){
|
||||||
const std::string &s=i<gs.squares_hl.size() ? gs.squares_hl[i] : squares_hl[i-gs.squares_hl.size()];
|
const GameState::Square &s=i<gs.squares_hl.size() ? gs.squares_hl[i] : squares_hl[i-gs.squares_hl.size()];
|
||||||
std::uint8_t sfile = s[0]-'a';
|
std::uint8_t sfile = s.square[0]-'a';
|
||||||
std::uint8_t srank = s[1]-'1';
|
std::uint8_t srank = s.square[1]-'1';
|
||||||
if (!black_side) {
|
if (!black_side) {
|
||||||
srank = 7 - srank;
|
srank = 7 - srank;
|
||||||
sfile = 7 - sfile;
|
sfile = 7 - sfile;
|
||||||
}
|
}
|
||||||
if(srank == rank && sfile==file){
|
if(srank == rank && sfile==file){
|
||||||
char type='a';
|
|
||||||
if(s.size()>2)
|
|
||||||
type=s[2];
|
|
||||||
// Default highlight (type='a' or something else not supported)
|
|
||||||
dc.SetPen(wxNullPen);
|
dc.SetPen(wxNullPen);
|
||||||
dc.SetBrush(wxColour(255, 102, 122));
|
if(s.color!=wxNullColour)
|
||||||
if(type=='b')
|
dc.SetBrush(s.color);
|
||||||
dc.SetBrush(wxColour(120, 255, 102));
|
else
|
||||||
else if(type=='c')
|
dc.SetBrush(wxColour(255, 102, 122));
|
||||||
dc.SetBrush(wxColour(102, 196, 255));
|
|
||||||
else if(type=='d')
|
|
||||||
dc.SetBrush(wxColour(255, 204, 213));
|
|
||||||
else if(type=='e')
|
|
||||||
dc.SetBrush(wxColour(220, 255, 204));
|
|
||||||
else if(type=='f')
|
|
||||||
dc.SetBrush(wxColour(204, 231, 255));
|
|
||||||
dc.DrawRectangle(wxRect(x,y,square_width,square_width));
|
dc.DrawRectangle(wxRect(x,y,square_width,square_width));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -396,12 +386,12 @@ void BoardCanvas::DrawBoard(wxDC &dc) {
|
||||||
boardY + square_width * 8 + numbers_size.y*2));
|
boardY + square_width * 8 + numbers_size.y*2));
|
||||||
}
|
}
|
||||||
// Draw arrows
|
// Draw arrows
|
||||||
for(int i=0;i<(gs.arrows.size()+arrows.size());i++){
|
for(int i=0;i<(gs.arrows.size()+arrows.size());i++){
|
||||||
const std::string &arrow= i<gs.arrows.size() ? gs.arrows[i] : arrows[i-gs.arrows.size()];
|
const GameState::Arrow &arrow= i<gs.arrows.size() ? gs.arrows[i] : arrows[i-gs.arrows.size()];
|
||||||
std::uint8_t sfile = arrow[0]-'a';
|
std::uint8_t sfile = arrow.src[0]-'a';
|
||||||
std::uint8_t srank = arrow[1]-'1';
|
std::uint8_t srank = arrow.src[1]-'1';
|
||||||
std::uint8_t dfile = arrow[2]-'a';
|
std::uint8_t dfile = arrow.dst[0]-'a';
|
||||||
std::uint8_t drank = arrow[3]-'1';
|
std::uint8_t drank = arrow.dst[1]-'1';
|
||||||
if (!black_side) {
|
if (!black_side) {
|
||||||
srank = 7 - srank;
|
srank = 7 - srank;
|
||||||
sfile = 7 - sfile;
|
sfile = 7 - sfile;
|
||||||
|
@ -414,37 +404,20 @@ void BoardCanvas::DrawBoard(wxDC &dc) {
|
||||||
std::uint32_t dy = boardY + drank * square_width + square_width/2;
|
std::uint32_t dy = boardY + drank * square_width + square_width/2;
|
||||||
|
|
||||||
// Parse arrow for metadata (maybe having a datatype is better)
|
// Parse arrow for metadata (maybe having a datatype is better)
|
||||||
std::uint8_t thickness=50;
|
if(arrow.color!=wxNullColour)
|
||||||
if(arrow.size()>4){
|
dc.SetBrush(arrow.color);
|
||||||
std::string color="#";
|
else
|
||||||
std::string new_thickness="";
|
|
||||||
char key='?';
|
|
||||||
for(const char &c:arrow){
|
|
||||||
if(c=='#'||c=='%'){
|
|
||||||
key=c;
|
|
||||||
continue;
|
|
||||||
}else if(key=='#'){
|
|
||||||
color+=c;
|
|
||||||
} else if(key=='%'){
|
|
||||||
new_thickness+=c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(color.size()>1)
|
|
||||||
dc.SetBrush(wxColour(color));
|
|
||||||
if(new_thickness.size()>0)
|
|
||||||
thickness=(std::uint8_t)std::stoi(new_thickness);
|
|
||||||
} else
|
|
||||||
dc.SetBrush(color_arrows);
|
dc.SetBrush(color_arrows);
|
||||||
if(((abs(drank-srank) == 2) && (abs(dfile-sfile) == 1))||
|
if(((abs(drank-srank) == 2) && (abs(dfile-sfile) == 1))||
|
||||||
((abs(drank-srank) == 1) && (abs(dfile-sfile) == 2))){
|
((abs(drank-srank) == 1) && (abs(dfile-sfile) == 2))){
|
||||||
if(abs(drank-srank) == 1){
|
if(abs(drank-srank) == 1){
|
||||||
DrawLArrow(dc,sx,sy,dx,dy,false,thickness);
|
DrawLArrow(dc,sx,sy,dx,dy,false,arrow_thickness*arrow.scale);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
DrawLArrow(dc,sx,sy,dx,dy,true,thickness);
|
DrawLArrow(dc,sx,sy,dx,dy,true,arrow_thickness*arrow.scale);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DrawArrow(dc,sx,sy,dx,dy,thickness);
|
DrawArrow(dc,sx,sy,dx,dy,arrow_thickness*arrow.scale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -519,14 +492,22 @@ void BoardCanvas::MouseEvent(wxMouseEvent &event) {
|
||||||
std::to_string(+active_square.y + 1);
|
std::to_string(+active_square.y + 1);
|
||||||
std::string dst=((char)('a' + file)) + std::to_string(rank + 1);
|
std::string dst=((char)('a' + file)) + std::to_string(rank + 1);
|
||||||
if(src!=dst){
|
if(src!=dst){
|
||||||
arrows.push_back(src+dst);
|
arrows.push_back(DEFAULT_ARROW(src,dst));
|
||||||
wxLogDebug("Draw arrow %s",src+dst);
|
wxLogDebug("Draw arrow %s",src+dst);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(std::count(squares_hl.begin(), squares_hl.end(), src)){
|
int id=0;
|
||||||
squares_hl.erase(std::remove(squares_hl.begin(), squares_hl.end(), src), squares_hl.end());
|
bool removed=false;
|
||||||
}else{
|
for(GameState::Square &s:squares_hl){
|
||||||
squares_hl.push_back(src+"f");
|
if(s.square==src){
|
||||||
|
squares_hl.erase(squares_hl.begin()+id);
|
||||||
|
removed=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
if(!removed){
|
||||||
|
squares_hl.push_back(DEFAULT_SQUARE(src));
|
||||||
wxLogDebug("Highlight square %s",src);
|
wxLogDebug("Highlight square %s",src);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -548,6 +529,7 @@ void BoardCanvas::Zoom(std::int32_t zoom) {
|
||||||
if(!t->Zoom(zoom))
|
if(!t->Zoom(zoom))
|
||||||
return;
|
return;
|
||||||
t_captures->ResizePieces(t->GetPiecesSizes() * CAPTURE_FACTOR);
|
t_captures->ResizePieces(t->GetPiecesSizes() * CAPTURE_FACTOR);
|
||||||
|
arrow_thickness = t->GetSquaresSizes()/1.8;
|
||||||
Refresh();
|
Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,8 @@ wxDECLARE_EVENT(PLAY_MOVE_EVENT, wxCommandEvent);
|
||||||
|
|
||||||
#define CAPTURE_FACTOR 0.35
|
#define CAPTURE_FACTOR 0.35
|
||||||
#define SQUARE_NUM_PADDING 5
|
#define SQUARE_NUM_PADDING 5
|
||||||
|
#define DEFAULT_ARROW(SRC,DST) {(SRC),(DST),wxNullColour,1}
|
||||||
|
#define DEFAULT_SQUARE(SQUARE) {(SQUARE),wxNullColour}
|
||||||
|
|
||||||
typedef std::tuple<short, short, short> ClockTime;
|
typedef std::tuple<short, short, short> ClockTime;
|
||||||
|
|
||||||
|
@ -61,11 +63,20 @@ typedef struct AnimState {
|
||||||
} AnimState;
|
} AnimState;
|
||||||
|
|
||||||
typedef struct GameState {
|
typedef struct GameState {
|
||||||
|
typedef struct Arrow {
|
||||||
|
std::string src,dst;
|
||||||
|
wxColour color=wxNullColour;
|
||||||
|
float scale=1;
|
||||||
|
} Arrow;
|
||||||
|
typedef struct Square {
|
||||||
|
std::string square;
|
||||||
|
wxColour color=wxNullColour;
|
||||||
|
} Square;
|
||||||
std::string white, black;
|
std::string white, black;
|
||||||
std::string board;
|
std::string board;
|
||||||
std::map<char, std::uint8_t> captures;
|
std::map<char, std::uint8_t> captures;
|
||||||
std::vector<std::string> squares_hl;
|
std::vector<Square> squares_hl;
|
||||||
std::vector<std::string> arrows;
|
std::vector<Arrow> arrows;
|
||||||
bool is_black_turn;
|
bool is_black_turn;
|
||||||
bool mat_black;
|
bool mat_black;
|
||||||
bool mat_white;
|
bool mat_white;
|
||||||
|
@ -78,10 +89,11 @@ class BoardCanvas : public wxPanel {
|
||||||
Theme *t, *t_captures;
|
Theme *t, *t_captures;
|
||||||
wxColour color_arrows;
|
wxColour color_arrows;
|
||||||
int arrows_offset;
|
int arrows_offset;
|
||||||
|
std::uint8_t arrow_thickness;
|
||||||
std::string white_player,black_player;
|
std::string white_player,black_player;
|
||||||
// Current highlighted squares and arrows:
|
// Current highlighted squares and arrows:
|
||||||
std::vector<std::string> squares_hl;
|
std::vector<GameState::Square> squares_hl;
|
||||||
std::vector<std::string> arrows;
|
std::vector<GameState::Arrow> arrows;
|
||||||
|
|
||||||
// Various canvas state variables
|
// Various canvas state variables
|
||||||
bool black_side, is_dragging, valid_drag, arrow_drag, is_black_turn;
|
bool black_side, is_dragging, valid_drag, arrow_drag, is_black_turn;
|
||||||
|
|
|
@ -101,23 +101,31 @@ void LiveEngineDialog::StartEngine() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LiveEngineDialog::OnTimerTick(wxTimerEvent &event) {
|
void LiveEngineDialog::OnTimerTick(wxTimerEvent &event) {
|
||||||
wxLogDebug("Tick!");
|
lines_list->DeleteAllItems(); // Clear lines_list
|
||||||
lines_list->DeleteAllItems();
|
|
||||||
engine->SyncAfter(0);
|
engine->SyncAfter(0);
|
||||||
EngineEvaluation *eval=new EngineEvaluation();
|
EngineEvaluation *eval=new EngineEvaluation();
|
||||||
auto const &lines=engine->GetLines();
|
auto lines=engine->GetLines(); // First best lines
|
||||||
eval->best_lines.resize(lines.size());
|
|
||||||
for (auto const &line : lines) {
|
// First retrieve lines ids from unordered map lines
|
||||||
long index = lines_list->InsertItem(0, std::to_string(line.first));
|
std::vector<int> ids;
|
||||||
|
for(auto const &line : lines){
|
||||||
|
ids.push_back(line.first);
|
||||||
|
}
|
||||||
|
std::sort(ids.begin(),ids.end());
|
||||||
|
|
||||||
|
// Now fill eval and lines_list
|
||||||
|
for (int &id:ids) {
|
||||||
|
auto const &line=lines[id];
|
||||||
|
long index = lines_list->InsertItem(id, std::to_string(id));
|
||||||
|
// Update eval that will be deplayed on the board
|
||||||
|
if(line.pv.size()>0)
|
||||||
|
eval->best_lines.push_back(line.pv[0]);
|
||||||
|
// Refresh lines_list
|
||||||
std::string line_moves;
|
std::string line_moves;
|
||||||
for (std::string move : line.second.pv) {
|
for (std::string move : line.pv)
|
||||||
line_moves += move + " ";
|
line_moves += move + " ";
|
||||||
}
|
std::string cp_str = std::to_string(line.score_cp);
|
||||||
if(line.second.pv.size()>0){
|
if (line.score_cp > 0) {
|
||||||
eval->best_lines.insert(eval->best_lines.begin()+line.first,line.second.pv[0]);
|
|
||||||
}
|
|
||||||
std::string cp_str = std::to_string(line.second.score_cp);
|
|
||||||
if (line.second.score_cp > 0) {
|
|
||||||
cp_str = "+" + cp_str;
|
cp_str = "+" + cp_str;
|
||||||
}
|
}
|
||||||
lines_list->SetItem(index, 1, cp_str);
|
lines_list->SetItem(index, 1, cp_str);
|
||||||
|
|
Loading…
Add table
Reference in a new issue