/** * @brief Graphics engine */ #include "graphics_sub.h" #include "engine.h" #include "text.h" #include "title.h" #include "kc_full.h" #define TEXT_TILE_OFFSET_SUB_0 6 #define TEXT_TILE_OFFSET_SUB_1 7 #define TEXT_TILE_MAP_SUB_0 BG_MAP_RAM_SUB(TEXT_TILE_OFFSET_SUB_0) #define TEXT_TILE_MAP_SUB_1 BG_MAP_RAM_SUB(TEXT_TILE_OFFSET_SUB_1) #define CLEAR_TEXT_TILE_MAP_0() memset(TEXT_TILE_MAP_SUB_0,0,32*48); #define CLEAR_TEXT_TILE_MAP_1() memset(TEXT_TILE_MAP_SUB_1,0,32*48); #define DRAW_TILE_AT_IDX(top,left) TEXT_TILE_MAP_SUB_0[(top) * 32 + (left)] #define SPRITE_WIDTH 32 #define SPRITE_HEIGHT 32 #define KC_ROT 0 #define KC_IDX 0 #define GFX_PTR_OFFSET(offset) (((u32)offset & 0xFFFFF) >> oamSub.gfxOffsetStep) #define SET_KC(gfxx) \ do { \ oamSub.oamMemory[KC_IDX].gfxIndex = GFX_PTR_OFFSET(gfxx); \ } while(false) #define MOVE_KC(xx, yy) \ do { \ oamSub.oamMemory[KC_IDX].x = (xx); \ oamSub.oamMemory[KC_IDX].y = (yy); \ } while(false) #define AFFINE_TRANSFORM(hx,vx,hy,vy)\ do { \ oamSub.oamRotationMemory[KC_ROT].hdx = hx;\ oamSub.oamRotationMemory[KC_ROT].vdx = vx;\ oamSub.oamRotationMemory[KC_ROT].hdy = hy;\ oamSub.oamRotationMemory[KC_ROT].vdy = vy;\ } while(false) #define SCALE_KC(x,y) AFFINE_TRANSFORM(256*x,0,0,256*y) u16* gfx_kc; u16* gfx_kc_val; u16* gfx_kc_inv; u16* gfx_kc_slot; #define SWITCH_KC_GRAPHICS(part,slot)\ do{\ if(slot >0 && part >0){\ if(slot == part){\ SET_KC(gfx_kc_val);\ }else{\ SET_KC(gfx_kc_inv);\ }\ }else if(slot > 0){\ SET_KC(gfx_kc_slot);\ }else if (part > 0){\ SET_KC(gfx_kc);\ }else{\ SET_KC(gfx_kc_slot);\ }\ }while(false) u8 loading_screen_id = 0; #define LOADING_SCREEN_COUNT 2 void configure_graphics_sub() { videoSetModeSub(MODE_5_2D); vramSetBankC(VRAM_C_SUB_BG_0x06200000); bgInitSub(0, BgType_Text8bpp, BgSize_T_256x256, TEXT_TILE_OFFSET_SUB_0, 0); bgInitSub(1, BgType_Text8bpp, BgSize_T_256x256, TEXT_TILE_OFFSET_SUB_1, 0); bgInitSub(2, BgType_Bmp8, BgSize_B8_256x256, 1, 0); REG_BG2PA_SUB = 256; REG_BG2PC_SUB = 0; REG_BG2PB_SUB = 0; REG_BG2PD_SUB = 256; bgSetPriority(0,2); bgSetPriority(1,1); bgSetPriority(2,3); swiCopy(titleBitmap + loading_screen_id * 64 * 192, BG_BMP_RAM_SUB(1), SCREEN_WIDTH * SCREEN_HEIGHT); swiCopy(textTiles, BG_TILE_RAM_SUB(0), textTilesLen); CLEAR_TEXT_TILE_MAP_0(); CLEAR_TEXT_TILE_MAP_1(); } void create_palette_sub() { vramSetBankH(VRAM_H_SUB_BG_EXT_PALETTE); swiCopy(titlePal, BG_PALETTE_SUB, titlePalLen); SET_PERSONAL_PALETTE(BG_PALETTE_SUB); } void create_object_sub() { vramSetBankD(VRAM_D_SUB_SPRITE); vramSetBankI(VRAM_I_SUB_SPRITE_EXT_PALETTE); oamInit(&oamSub, SpriteMapping_1D_32, false); gfx_kc = oamAllocateGfx(&oamSub, SpriteSize_32x64, SpriteColorFormat_256Color); gfx_kc_val = oamAllocateGfx(&oamSub, SpriteSize_32x64, SpriteColorFormat_256Color); gfx_kc_inv = oamAllocateGfx(&oamSub, SpriteSize_32x64, SpriteColorFormat_256Color); gfx_kc_slot = oamAllocateGfx(&oamSub, SpriteSize_32x64, SpriteColorFormat_256Color); //Copy data for the graphic (palette and bitmap) swiCopy(kc_fullPal, SPRITE_PALETTE_SUB, kc_fullPalLen); swiCopy(kc_fullTiles, gfx_kc, kc_fullTilesLen / (2 * 4)); swiCopy(kc_fullTiles + (64 * 8), gfx_kc_val, kc_fullTilesLen / (2 * 4)); swiCopy(kc_fullTiles + (64 * 16), gfx_kc_inv, kc_fullTilesLen / (2 * 4)); swiCopy(kc_fullTiles + (64 * 24), gfx_kc_slot, kc_fullTilesLen / (2 * 4)); oamSet(&oamSub, KC_IDX, SCREEN_WIDTH, 0, 0, 0, SpriteSize_32x64, SpriteColorFormat_256Color, gfx_kc, KC_ROT, false, false, false, false, false); } void switch_mode_sub(gmode_t mode) { switch (mode) { case GGAME: CLEAR_TEXT_TILE_MAP_0(); CLEAR_TEXT_TILE_MAP_1(); SET_PERSONAL_PALETTE(BG_PALETTE_SUB); break; case GMENU: CLEAR_TEXT_TILE_MAP_0(); CLEAR_TEXT_TILE_MAP_1(); swiCopy(titlePal, BG_PALETTE_SUB, titlePalLen); swiCopy(titleBitmap + loading_screen_id * 64 * 192, BG_BMP_RAM_SUB(1), SCREEN_WIDTH * SCREEN_HEIGHT); MOVE_KC(SCREEN_WIDTH, SCREEN_HEIGHT); break; case GGAME_ALT: CLEAR_TEXT_TILE_MAP_0(); CLEAR_TEXT_TILE_MAP_1(); memset(BG_BMP_RAM_SUB(1), 0, SCREEN_WIDTH * SCREEN_HEIGHT); swiCopy(textPal, BG_PALETTE_SUB, textPalLen); MOVE_KC(SCREEN_WIDTH, SCREEN_HEIGHT); break; } } void next_loading_isr(u8 f) { ++loading_screen_id; if (loading_screen_id >= LOADING_SCREEN_COUNT || f != 0) { loading_screen_id = LOADING_SCREEN_COUNT; } } void draw_title_sub() { swiCopy(titleBitmap + loading_screen_id * 64 * 192, BG_BMP_RAM_SUB(1), SCREEN_WIDTH * SCREEN_HEIGHT); MOVE_KC(SCREEN_WIDTH, SCREEN_HEIGHT); } u8 hit_kc = 0; u8 screen_buff[SCREEN_WIDTH * SCREEN_HEIGHT] = {0}; void draw_vertical_line(const u32 col, const position_t* const pos, const room_t room, const s16 slot_left) { s16 angle = MOD((pos->r - (FOV / 2) + (col * FOV) / (SCREEN_WIDTH * 1.0)), 360); float32 raydir_x = fixedToFloat(sinLerp(degreesToAngle(angle)), 12); float32 raydir_y = fixedToFloat(cosLerp(degreesToAngle(angle)), 12); s16 map_x = (s16)(pos->x); s16 map_y = (s16)(pos->y); float32 delta_dist_x = ABS(1.0 / raydir_x); float32 delta_dist_y = ABS(1.0 / raydir_y); float32 perp_dist = 0.1; s8 step_x; s8 step_y; float32 border_dist_x; float32 border_dist_y; if (raydir_x < 0) { step_x = -1; border_dist_x = (pos->x - map_x) * delta_dist_x; } else { step_x = 1; border_dist_x = (map_x + 1.0 - pos->x) * delta_dist_x; } if (raydir_y < 0) { step_y = -1; border_dist_y = (pos->y - map_y) * delta_dist_y; } else { step_y = 1; border_dist_y = (map_y + 1.0 - pos->y) * delta_dist_y; } u8 side = 0; u8 hit = 0; part_t slot = get_slot_id(room); part_t part = get_part_id(room); while (hit == 0) { if (border_dist_x < border_dist_y) { border_dist_x += delta_dist_x; map_x += step_x; side = 0; } else { border_dist_y += delta_dist_y; map_y += step_y; side = 1; } if ((slot > 0 || part > 0) && (map_x-1 == ROOM_SIZE / 2) && map_y-1 == ROOM_SIZE / 2) { hit_kc = 1; if (side == 0) { perp_dist = (map_x - pos->x + (1.0 - step_x) / 2.0) / raydir_x; } else { perp_dist = (map_y - pos->y + (1.0 - step_y) / 2.0) / raydir_y; } s16 lheight = (s16)(SCREEN_HEIGHT / perp_dist); s16 lpos = MAX(0, -lheight / 2 + SCREEN_HEIGHT / 2); SCALE_KC(MAX(1, perp_dist), MAX(1, perp_dist)); MOVE_KC(col - 32, SCREEN_HEIGHT - lpos - 64 / MAX(1, perp_dist)); SWITCH_KC_GRAPHICS(part, slot); } if ((is_wall(map_x, map_y, room) != 0) || (is_door(map_x, map_y, room) != 0)) hit = 1; } if (side == 0) { perp_dist = (map_x - pos->x + (1.0 - step_x) / 2.0) / raydir_x; } else { perp_dist = (map_y - pos->y + (1.0 - step_y) / 2.0) / raydir_y; } s16 vheight = (SCREEN_HEIGHT / perp_dist); if(perp_dist <= 0) vheight = SCREEN_HEIGHT; s16 vstart = (SCREEN_HEIGHT / 2) - (vheight / 2); s16 vend = (SCREEN_HEIGHT / 2) + (vheight / 2); u16 color = (is_door(map_x, map_y, room) > 0) ? P_BLUE : ((is_wall(map_x, map_y, room) > 0) ? (check_room_has_element(room, RTRAP) ? P_VIOLET : P_WHITE) : P_TRANSPARENT); if (side == 1) { color = color + 1; } u8* buff = (u8*) screen_buff; u32 row; for (row = 0; row < SCREEN_HEIGHT; row++) { if (row < vstart) { buff[row * SCREEN_WIDTH + col] = P_DARK_DARK_WHITE; } else if (row <= vend) { buff[row * SCREEN_WIDTH + col] = color; } else { buff[row * SCREEN_WIDTH + col] = check_room_has_element(room, REXIT) ? (slot_left == 0 ? P_DARK_GREEN : P_DARK_RED) : P_DARK_DARK_WHITE; } } } void draw_view_sub(const position_t* const pos, const room_t room, const s16 left) { u32 col = 0; hit_kc = 0; for (col = 0; col < SCREEN_WIDTH; col++) { draw_vertical_line(col, pos, room, left); } swiCopy(screen_buff, BG_BMP_RAM_SUB(1), SCREEN_WIDTH * SCREEN_HEIGHT); if (hit_kc == 0) { MOVE_KC(SCREEN_WIDTH, SCREEN_HEIGHT); } } void draw_game_sub(const position_t* const pos, const room_t room, const s16 left) { draw_view_sub(pos, room, left); } static u16 elem_to_tile(room_elements elem){ switch(elem){ case NWALL: case SWALL: case WWALL: case EWALL: return 92; break; case RSLOT: return 93; break; case RPART: return 94; break; case RTRAP: return 95; break; case REXIT: return 96; break; } return 0; } #define NET_ROOM_SIZE 16 #define NET_DOOR_SIZE (NET_ROOM_SIZE/4) #define RMLO (16-NET_ROOM_SIZE/2) #define RMTO 3 #define RMDO (16-NET_DOOR_SIZE/2) void draw_game_multi_sub(const room_t room, const u32 slot_left){ memset(BG_BMP_RAM_SUB(1), 0, SCREEN_WIDTH * SCREEN_HEIGHT); u16 i; for(i = 0; i < NET_ROOM_SIZE; ++i){ DRAW_TILE_AT_IDX(RMTO,RMLO+i) = elem_to_tile(WWALL); DRAW_TILE_AT_IDX(RMTO+1,RMLO+i) = elem_to_tile(WWALL); DRAW_TILE_AT_IDX(RMTO+i,RMLO) = elem_to_tile(WWALL); DRAW_TILE_AT_IDX(RMTO+i,RMLO+1) = elem_to_tile(WWALL); DRAW_TILE_AT_IDX(RMTO+i,RMLO+NET_ROOM_SIZE-2) = elem_to_tile(WWALL); DRAW_TILE_AT_IDX(RMTO+i,RMLO+NET_ROOM_SIZE-1) = elem_to_tile(WWALL); DRAW_TILE_AT_IDX(RMTO+NET_ROOM_SIZE-2,RMLO+i) = elem_to_tile(WWALL); DRAW_TILE_AT_IDX(RMTO+NET_ROOM_SIZE-1,RMLO+i) = elem_to_tile(WWALL); } for (i = 0; i < NET_DOOR_SIZE; ++i) { if(!check_room_has_element(room, NWALL)){ DRAW_TILE_AT_IDX(RMTO,RMDO+i) = 0; DRAW_TILE_AT_IDX(RMTO+1,RMDO+i) = 0; } if (!check_room_has_element(room, SWALL)) { DRAW_TILE_AT_IDX(RMTO+NET_ROOM_SIZE-2,RMDO+i) = 0; DRAW_TILE_AT_IDX(RMTO+NET_ROOM_SIZE-1,RMDO+i) = 0; } if (!check_room_has_element(room, WWALL)) { DRAW_TILE_AT_IDX(RMTO+(NET_ROOM_SIZE/2)-(NET_DOOR_SIZE/2)+i,RMLO) = 0; DRAW_TILE_AT_IDX(RMTO+(NET_ROOM_SIZE/2)-(NET_DOOR_SIZE/2)+i,RMLO+1) = 0; } if (!check_room_has_element(room, EWALL)) { DRAW_TILE_AT_IDX(RMTO+(NET_ROOM_SIZE/2)-(NET_DOOR_SIZE/2)+i,RMLO+NET_ROOM_SIZE-2) = 0; DRAW_TILE_AT_IDX(RMTO+(NET_ROOM_SIZE/2)-(NET_DOOR_SIZE/2)+i,RMLO+NET_ROOM_SIZE-1) = 0; } } for (i = 0; i < ELEM_SIZE; ++i) { if(check_room_has_element(room, RSLOT)){ u16 j; for(j=0; j< ELEM_SIZE; ++j){ DRAW_TILE_AT_IDX(RMTO+(NET_ROOM_SIZE/2) - ELEM_SIZE/2+i, 16-2 + j)= elem_to_tile(RSLOT); } } if(check_room_has_element(room, RPART)){ u16 j; for(j=0; j< ELEM_SIZE; ++j){ DRAW_TILE_AT_IDX(RMTO+(NET_ROOM_SIZE/2) - ELEM_SIZE/2+1+i/2, 16-1 + j/2)= elem_to_tile(RPART); } } if(check_room_has_element(room, REXIT)){ u16 spridx = elem_to_tile(REXIT) + ((slot_left == 0)?0:1); DRAW_TILE_AT_IDX(RMTO+(ELEM_SIZE/2)+i - 2*(i/2), RMLO+(ELEM_SIZE/2) + i/2)= spridx; DRAW_TILE_AT_IDX(RMTO+(ELEM_SIZE/2)+i - 2*(i/2), RMLO+NET_ROOM_SIZE-(ELEM_SIZE) + i/2)= spridx; DRAW_TILE_AT_IDX(RMTO+NET_ROOM_SIZE-(ELEM_SIZE)+i - 2*(i/2), RMLO+NET_ROOM_SIZE-(ELEM_SIZE) + i/2)= spridx; DRAW_TILE_AT_IDX(RMTO+NET_ROOM_SIZE-(ELEM_SIZE)+i - 2*(i/2), RMLO+(ELEM_SIZE/2) + i/2)= spridx; } if(check_room_has_element(room, RTRAP)){ DRAW_TILE_AT_IDX(RMTO+i - 2*(i/2), RMLO + i/2)= elem_to_tile(RTRAP) ; DRAW_TILE_AT_IDX(RMTO+i - 2*(i/2), RMLO+NET_ROOM_SIZE-(ELEM_SIZE/2) + i/2)= elem_to_tile(RTRAP); DRAW_TILE_AT_IDX(RMTO+NET_ROOM_SIZE-(ELEM_SIZE/2)+i - 2*(i/2), RMLO+NET_ROOM_SIZE-(ELEM_SIZE/2) + i/2)= elem_to_tile(RTRAP); DRAW_TILE_AT_IDX(RMTO+NET_ROOM_SIZE-(ELEM_SIZE/2)+i - 2*(i/2), RMLO + i/2)= elem_to_tile(RTRAP); } } } void draw_player_multi_sub(const net_player_t* const player, const bool ghost){ TEXT_TILE_MAP_SUB_1[(RMTO+player->y) * 32 + (RMLO+player->x)] = elem_to_tile(REXIT)+1; TEXT_TILE_MAP_SUB_0[(RMTO+player->y) * 32 + (RMLO+player->x)] = char_to_tile('A');//player->name[0]); }