epfl-archive/ee310-mes/source/graphics_sub.c
2022-04-07 18:46:57 +02:00

414 lines
12 KiB
C

/**
* @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]);
}