#include "chess/bishop.hpp" #include "chess/king.hpp" #include "chess/knight.hpp" #include "chess/pawn.hpp" #include "chess/queen.hpp" #include "chess/rook.hpp" #include "chess/square.hpp" #include "chess/circle.hpp" #include "chess/pointer.hpp" #include "sh7091/store_queue.hpp" #include "sh7091/serial.hpp" #include "holly/ta_parameter.hpp" #include "holly/isp_tsp.hpp" #include "holly/ta_global_parameter.hpp" #include "holly/ta_vertex_parameter.hpp" #include "chess/chess.hpp" #include "chess/render.hpp" namespace render { constexpr float board_z = 100.f; constexpr float illumination_z = 99.f; constexpr float piece_z = 70.f; constexpr float move_z = 50.f; constexpr float cursor_z = 0.f; vec3 __attribute__ ((noinline)) transform(view_transform vt, const vec3 v, float cell_x, float cell_y, float z_offset, float scale, float rotation) { float x0 = v.x; float y0 = -v.y; // piece rotation float x1 = x0 * __builtin_cosf(rotation) - y0 * __builtin_sinf(rotation); float y1 = x0 * __builtin_sinf(rotation) + y0 * __builtin_cosf(rotation); float x2 = x1 * 28.f * scale; float y2 = y1 * 28.f * scale; float x3 = x2 + (cell_x ) * 56.f - (196.f); float y3 = y2 + (7 - cell_y) * 56.f - (196.f); float x4 = x3 * __builtin_cosf(vt.board_rotation) - y3 * __builtin_sinf(vt.board_rotation); float y4 = x3 * __builtin_sinf(vt.board_rotation) + y3 * __builtin_cosf(vt.board_rotation); float x5 = x4 + 124.f + (196.f); float y5 = y4 + 44.f + (196.f); float z = v.z + z_offset; return {x5, y5, 1.f/(z + 10.0f)}; } static void draw_model(const view_transform vt, vec3 const * const vertices, face_v const * const faces, uint32_t num_faces, uint32_t base_color, float cell_x, float cell_y, float z_offset, float scale, float rotation, bool always, bool alpha = false) { const uint32_t parameter_control_word = para_control::para_type::polygon_or_modifier_volume | para_control::list_type::translucent | obj_control::col_type::packed_color; const uint32_t isp_tsp_instruction_word = (always ? isp_tsp_instruction_word::depth_compare_mode::greater : isp_tsp_instruction_word::depth_compare_mode::greater) | isp_tsp_instruction_word::culling_mode::no_culling; const uint32_t tsp_instruction_word = (alpha ? tsp_instruction_word::src_alpha_instr::src_alpha : tsp_instruction_word::src_alpha_instr::one) | (alpha ? tsp_instruction_word::dst_alpha_instr::inverse_src_alpha : tsp_instruction_word::dst_alpha_instr::zero) | tsp_instruction_word::fog_control::no_fog | tsp_instruction_word::use_alpha; for (uint32_t face_ix = 0; face_ix < num_faces; face_ix++) { *reinterpret_cast(store_queue) = ta_global_parameter::polygon_type_0(parameter_control_word, isp_tsp_instruction_word, tsp_instruction_word, 0, // texture_control_word 0, // data_size_for_sort_dma 0 // next_address_for_sort_dma ); sq_transfer_32byte(ta_fifo_polygon_converter); auto& face = faces[face_ix]; constexpr uint32_t strip_length = 3; for (uint32_t i = 0; i < strip_length; i++) { uint32_t vertex_ix = face[i].vertex; const auto vertex = transform(vt, vertices[vertex_ix], cell_x, cell_y, z_offset, scale, rotation); bool end_of_strip = i == strip_length - 1; float z = __builtin_fabsf(vertices[vertex_ix].z); uint32_t color = (z < 0.9f && z > 0.1f) ? 0xff000000 : base_color; *reinterpret_cast(store_queue) = ta_vertex_parameter::polygon_type_0(polygon_vertex_parameter_control_word(end_of_strip), vertex.x, vertex.y, vertex.z, color); sq_transfer_32byte(ta_fifo_polygon_converter); } } } void draw_board(const view_transform vt) { for (int i = 0; i < 8 * 8; i++) { int x = i % 8; int y = i / 8; bool white = (x % 2 == 0) ^ (y % 2 == 0); constexpr uint32_t cream = 0xffebecd0; constexpr uint32_t green = 0xff739552; uint32_t color = white ? cream : green; draw_model(vt, square::vertices, square::faces, square::num_faces, color, x, y, board_z, 1.0f, // scale 0.0f, // rotation true); // always } } void draw_illumination(const view_transform vt, int8_t position, uint32_t highlight_color) { auto [x, y] = chess::position_to_xy(position); draw_model(vt, square::vertices, square::faces, square::num_faces, highlight_color, x, y, illumination_z, 1.0f, // scale 0.0f, // rotation true, // always true); // alpha } void draw_moves(const view_transform vt, const chess::moves_list& moves) { for (int i = 0; i < moves.length; i++) { chess::xy move_xy = chess::position_to_xy(moves.moves[i].to_position); uint32_t color = 0x37000000; draw_model(vt, circle::vertices, circle::faces, circle::num_faces, color, move_xy.x, move_xy.y, move_z, 0.4f, // scale 0.0f, // rotation true, // always true); // alpha } } void draw_piece(const view_transform vt, int8_t type, int8_t x, int8_t y) { bool white = type > 0; uint32_t color = white ? 0xffdddddd : 0xff444444; switch (__builtin_abs(type)) { case chess::piece_type::pawn: draw_model(vt, pawn::vertices, pawn::faces, pawn::num_faces, color, x, y, piece_z, 1.0f, // scale vt.piece_rotation, // rotation false); // always break; case chess::piece_type::knight: draw_model(vt, knight::vertices, knight::faces, knight::num_faces, color, x, y, piece_z, 1.0f, // scale vt.piece_rotation, // rotation false); // always break; case chess::piece_type::bishop: draw_model(vt, bishop::vertices, bishop::faces, bishop::num_faces, color, x, y, piece_z, 1.0f, // scale vt.piece_rotation, // rotation false); // always break; case chess::piece_type::rook: draw_model(vt, rook::vertices, rook::faces, rook::num_faces, color, x, y, piece_z, 1.0f, // scale vt.piece_rotation, // rotation false); // always break; case chess::piece_type::queen: draw_model(vt, queen::vertices, queen::faces, queen::num_faces, color, x, y, piece_z, 1.0f, // scale vt.piece_rotation, // rotation false); // always break; case chess::piece_type::king: draw_model(vt, king::vertices, king::faces, king::num_faces, color, x, y, piece_z, 1.0f, // scale vt.piece_rotation, // rotation false); // always break; default: break; } } void draw_pieces(const view_transform vt, const chess::game_state& game_state) { const auto& piece_list = game_state.piece_list; for (int i = 0; i < piece_list.length; i++) { chess::piece * piece = piece_list.piece[i]; int8_t position = piece_list_to_position(game_state.board, piece); auto [x, y] = chess::position_to_xy(position); draw_piece(vt, piece->type, x, y); } } uint32_t cursor_colors[4] = { 0xffff00ff, 0xff00ff00, 0xffffff00, 0xffff0000, }; void draw_cursor(const view_transform vt, float x, float y, int cursor_index) { constexpr float pi = 3.141592653589793f; draw_model(vt, pointer::vertices, pointer::faces, pointer::num_faces, cursor_colors[cursor_index % 4], x, y, cursor_z, 1.0f, // scale pi * cursor_index, // rotation true); // always } void draw_annotation(const view_transform vt, const chess::annotation_list& annotation_list) { constexpr uint32_t red_highlight = 0xcceb6150; for (int i = 0; i < annotation_list.length; i++) { auto& annotation = annotation_list.annotation[i]; switch (annotation.type) { case chess::annotation_type::highlight: render::draw_illumination(vt, annotation.from_position, red_highlight); break; default: break; } } } void draw_interaction(const view_transform vt, const chess::interaction_state& interaction) { constexpr uint32_t yellow_highlight = 0x7fffff33; if (interaction.selected_position != -1) render::draw_illumination(vt, interaction.selected_position, yellow_highlight); if (interaction.last_move.from_position != -1) render::draw_illumination(vt, interaction.last_move.from_position, yellow_highlight); if (interaction.last_move.to_position != -1) render::draw_illumination(vt, interaction.last_move.to_position, yellow_highlight); } void render(const chess::game_state& game_state, const view_transform vt, const cursor_state cursor_state) { render::draw_board(vt); render::draw_interaction(vt, game_state.interaction); render::draw_annotation(vt, game_state.interaction.annotation_list); render::draw_pieces(vt, game_state); render::draw_moves(vt, game_state.interaction.moves); for (int i = 0; i < cursor_state::num_cursors; i++) { auto& cursor = cursor_state.cur[i]; render::draw_cursor(vt, cursor.x, cursor.y, i); } } } // namespace render