I don't know enough about Chinook, and neither are a good enough Xiangqi player to have a sensible opinion on that.
I have started coding my XQ engine based on the following design, now:
There is a piece list, which contains for eache piece both a pointer to a bitmap (u64 *typeMap), and a pointer to a board of bitmaps (u64 *squareMask), indicating which bits in the typeMap have to change when the piece enters or leaves a given square. So the MakeMove() routine contains a statement
typeMap[piece] ^= squareMask[piece][from] ^ squareMask[piece][to] ^squareMask[victim][to];
This is used for different purposes on different pieces, though: for the weak pieces (unpromoted P,E,A,K) it contains their packed attack maps. This can have multiple bits set per square, as a single piece on a single square can attack multiple squares. But all set bits belong to the same piece. For the strong pieces (promoted P (=Q), H, C, R) it contains the squares they are on, with the same encoding as the attack sets. This can also have multiple bits set, as a given square can occur in several attack sets. (e.g. e1 kan be in the attack set of K and each advisor.) C and H share the same map (since they are approximately equally valuable).
The piece list is divided in 4 'victim groups': Rooks, Cannons+Horses, Advisors+promoted Pawns, Elephants+unpromoted Pawns. King is not in a victim group, as moves that put the King in check are never made. The capture moves are generated by 3 nested loops: the outer loop iterates through the victim groups, starting with R, (Most Valuable Victim), and ending with E+P. For each victim group we then iterate through the possible attckers, low to high. This start by intersecting the position map of the (opponent's) victim group with the attack set of the weak pieces. The E+P group uses a dummy map for this, which is always zero. After that, the middle loop iterates through the remaining attackers individually (Q,H,C,R), and then performs a 0x88-style alignment test in the inner loop with all possible victims of the current victim group. (For Q attackers probing the board directly in 3 places for attacking Q around the victim might actually be faster than a 0x88 test on all P and Q.)
There are potentially 15 victims in the combined victim groups, and typically 6 pieces (other than PEAK) to attack them. This would require 60 attack tests, consisting of subtracting the square numbers of attacker and victm, an using the difference for a table lookup (to typically find there is no alignment; in the rare case there is alignment a ray scan is necessary to see if there is an actual capture). For comparison: using a 'direct' move generator (starting from the moving piece, rather than the victim) would require generating of moves in 8 directions each for 2 Horses, and 4 drections each for 2 Cannons and 2 Rooks. In total 32 directions, and in half of those (for C+R) a ray scan would always be required. (And the Horses also need testing if their moves are blocked.) It is not obvious which is more work.
But as the board grows emptier, the work involved in direct generation decreases linearly, or even worse, as the ra scans tend to reach further. With the 'inverted' generation (towards victims) the work decreases quadratically, as both nmber of victims and attackers decreases. In addition, the direct generation always has to be performed upto the end, to be sure you have found the MVV, and then requires sorting, or at least extraction of themove with the best MVV/LVA. The inverted generation does produce the captures in MVV/LVA order, so you can search them immediately as they are generated. In cut-nodes this means you might not need many attack tests at all, becase the first move you find already causes a cutoff. And in all-nodes, the lightest victims might be futile, and they are most abundant. E.g. if currentEval < alpha - 200 all captures on E+P are futile, (E=150, P=100), and that exempts 7 of the 15 victims, cutting the work nearly by 50%. So even with all material still on the board, I think the inverted capture generation is competitive, and it starts winning big time when the material thins out.