#include "render.h" SDL_Window *window; SDL_Renderer *renderer; TTF_Font *RobotoFont; SDL_DisplayMode screenDimension; SDL_Rect destRect; SDL_Rect rect; SDL_Rect sky; SDL_Rect ground; SDL_Texture * netTexture; SDL_Texture * crowdTexture; SDL_Texture * playerTexture; int ** rays; int raysListLength = 0; int * ray1; int * ray2; rayInfo_t raysListHead; float fps; SDL_Texture * loadTexture(char * path) { SDL_Surface * surface = IMG_Load(path); SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, surface); SDL_FreeSurface(surface); return texture; } void addRayInfoToList(rayInfo_t * rayInfoHead, rayInfo_t * rayInfo) { rayInfo->next = rayInfoHead->next; rayInfoHead->next = rayInfo; } void freeRayInfoList(rayInfo_t * rayInfoHead) { rayInfo_t * rayInfo = rayInfoHead->next; while (rayInfo != NULL) { //printf("freeing : %p\n", rayInfo); rayInfo_t * next = rayInfo->next; free(rayInfo); rayInfo = next; } } rayInfo_t * allocRayInfo(float ra, float distT, int r, int isTransparent, int direction, float htexture){ rayInfo_t * rayInfo = malloc(sizeof(rayInfo_t)); if (rayInfo == NULL) { printf("Error: malloc failed\n"); exit(1); } rayInfo->ra = ra; rayInfo->distT = distT; rayInfo->r = r; rayInfo->isTransparent = isTransparent; rayInfo->direction = direction; rayInfo->htexture = htexture; rayInfo->next = NULL; return rayInfo; } void initRays(){ int i; rays = malloc(sizeof(int*) * 2 * NB_RAYS); for (i = 0; i < NB_RAYS * 2; i++){ rays[i] = malloc(sizeof(int) * 2); } } int isRaysListEmpty(){ return raysListLength == 0; } void addRayToList(int x, int y){ if (raysListLength < 2 * NB_RAYS){ *rays[raysListLength] = x; *(rays[raysListLength] + 1) = y; raysListLength++; } } void resetRayList(){ int i; for (i = 0; i < 2 * NB_RAYS; i++){ *rays[i] = 0; *(rays[i] + 1) = 0; } raysListLength = 0; } // end ray casting variables void createWindow(){ if (SDL_Init(SDL_INIT_VIDEO) != 0){ printf("Couldn't create window."); exit(EXIT_FAILURE); } SDL_GetCurrentDisplayMode(0, &screenDimension); window = SDL_CreateWindow("Mat Le King", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, screenDimension.w, screenDimension.h, SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_SHOWN | SDL_WINDOW_FULLSCREEN_DESKTOP); if (window == NULL){ printf("Couldn't create window"); exit(EXIT_FAILURE); } renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE | SDL_RENDERER_PRESENTVSYNC); if (renderer == NULL){ printf("Couldn't create renderer."); exit(EXIT_FAILURE); } if (TTF_Init() == -1) { exit(EXIT_FAILURE); } RobotoFont = TTF_OpenFont("Res/Roboto-Black.ttf", 50); } void endSDL(){ SDL_DestroyWindow(window); SDL_DestroyRenderer(renderer); TTF_CloseFont(RobotoFont); TTF_Quit(); SDL_Quit(); } void drawRayColumn(rayInfo_t * rayInfo){ float ca = player.angle - rayInfo->ra; if (ca < 0) ca += 2*pi; if (ca > 2*pi) ca -= 2*pi; rayInfo->distT = rayInfo->distT * cos(ca); float lineH = (screenDimension.h/2)/rayInfo->distT; rect.x = rayInfo->r; rect.y = (screenDimension.h/2 + player.viewAngle) - lineH; rect.w = 1; rect.h = (2 * screenDimension.w * lineH/20); destRect.x = rayInfo->htexture; destRect.y = 0; destRect.w = 1; destRect.h = 64; if (rayInfo->isTransparent){ rect.h *= 1.75; rect.y -= rect.h/3; SDL_RenderCopy(renderer, netTexture, &destRect, &rect); } else { destRect.x += + 64 * (SDL_GetTicks()/200 % 4); if (rayInfo->direction){ SDL_RenderCopy(renderer, crowdTexture, &destRect, &rect); } else { SDL_RenderCopy(renderer, crowdTexture, &destRect, &rect); } } } void drawVerticalRays(){ rayInfo_t * current = raysListHead.next; while (current != NULL){ //printf("%p\n", current); if (current->direction){ drawRayColumn(current); } current = current->next; } } void drawHorizentalRays(){ rayInfo_t * current = raysListHead.next; while (current != NULL){ //printf("%p\n", current); if (!current->direction){ drawRayColumn(current); } current = current->next; } } void castRays(int map[][MAP_WIDTH]){ // ray casting variables float htexture, htexture2; int r, mx, my, dof; double rx, ry, rx2, ry2, xo, yo, distT, distT2; double ra; mx = 0; my = 0; resetRayList(); freeRayInfoList(&raysListHead); raysListHead.next = NULL; ra = player.angle - DR * FOV_ANGLE/4; if (ra < 0) ra -= 2*pi; if (ra > 2*pi) ra -= 2*pi; for (r = 0; r<NB_RAYS; r++){ // check horizontal rays //int foundTransparentWallH = 0; int foundSolidWallH = 0; dof = 0; float disH = 100000, disH2 = 100000, hx = player.x, hy = player.y , hx2 = player.x, hy2 = player.y; float aTan = -1/tan(ra); if (ra > pi){ // looking up ry = (((int)player.y>>6)<<6) - 0.0001; rx = (player.y - ry) * aTan + player.x; yo = -BLOCK_SIZE; xo = -yo*aTan; } if (ra<pi){ // looking down ry = (((int)player.y>>6)<<6) + BLOCK_SIZE; rx = (player.y - ry) * aTan + player.x; yo = BLOCK_SIZE; xo = -yo*aTan; } if (ra == pi){ ry = player.y; rx = player.x; dof = DOF; } while (dof < DOF){ mx = (int)rx>>6; my = (int)ry>>6; if (mx >= 0 && mx < MAP_WIDTH && my >= 0 && my < MAP_HEIGHT){ if (map[my][mx] == 1){ hx = rx; hy = ry; disH = sqrt((rx-player.x)*(rx-player.x) + (ry-player.y)*(ry-player.y)); dof = DOF; foundSolidWallH = 1; } else { hx2 = rx; hy2 = ry; disH2 = sqrt((rx-player.x)*(rx-player.x) + (ry-player.y)*(ry-player.y)); //foundTransparentWallH = 1; dof++; rx += xo; ry += yo; } } else { rx += xo; ry += yo; dof++; } } //printf("hx %f hy %f\n", hx, hy); // check vertical rays dof = 0; float disV = 100000, disV2 = 100000 , vx = player.x, vy = player.y, vx2, vy2; float nTan = -tan(ra); if (ra > pi/2 && ra < 3*pi/2){ // looking left rx = (((int)player.x>>6)<<6) - 0.0001; ry = player.y + (player.x - rx) * nTan; xo = -BLOCK_SIZE; yo = -xo*nTan; } if (ra<pi/2 || ra > 3*pi/2){ // looking right rx = (((int)player.x>>6)<<6) + BLOCK_SIZE; ry = player.y + (player.x - rx) * nTan; xo = BLOCK_SIZE; yo = -xo*nTan; } if (ra == pi || ra == 0){ ry = player.y; rx = player.x; dof = DOF; } int foundSolidWallV = 0; int foundTransparentWallV = 0; while (dof < DOF){ mx = (int)rx>>6; my = (int)ry>>6; if (mx >= 0 && mx < MAP_WIDTH && my >= 0 && my < MAP_HEIGHT && map[my][mx]){ if (map[my][mx] == 1){ vx = rx; vy = ry; disV = sqrt((rx-player.x)*(rx-player.x) + (ry-player.y)*(ry-player.y)); foundSolidWallV = 1; dof = DOF; } else { vx2 = rx; vy2 = ry; disV2 = sqrt((rx-player.x)*(rx-player.x) + (ry-player.y)*(ry-player.y)); foundTransparentWallV = 1; dof++; rx += xo; ry += yo; } } else { rx += xo; ry += yo; dof++; } } int direction, direction2; if (foundTransparentWallV){ if (disH < disV2){ rx = hx2; ry = hy2; distT = disH2; direction = 0; htexture = (int)(rx)%BLOCK_SIZE; } else { rx = vx2; ry = vy2; distT = disV2; direction = 1; htexture = (int)(ry)%BLOCK_SIZE; } if (foundSolidWallV){ if (disH < disV){ rx2 = hx; ry2 = hy; distT2 = disH; direction2 = 0; htexture2 = (int)(rx2)%BLOCK_SIZE; } else { rx2 = vx; ry2 = vy; distT2 = disV; direction2 = 1; htexture2 = (int)(ry2)%BLOCK_SIZE; } } if (foundSolidWallH){ if (disH < disV){ rx2 = hx; ry2 = hy; distT2 = disH; direction2 = 0; htexture2 = (int)(rx2)%BLOCK_SIZE; } else { rx2 = vx; ry2 = vy; distT2 = disV; direction2 = 1; htexture2 = (int)(ry2)%BLOCK_SIZE; } } } else { if (disH < disV) { rx = hx; ry = hy; distT = disH; direction = 0; htexture = (int)(rx)%BLOCK_SIZE; } else { rx = vx; ry = vy; distT = disV; direction = 1; htexture = (int)(ry)%BLOCK_SIZE; } } ra = ra + ANGLE_INC/2; if (ra > 2*pi) ra -= 2*pi; if (ra < 0) ra += 2*pi; // draw ray rayInfo_t * column = allocRayInfo(ra, distT, r, foundTransparentWallV, direction, htexture); addRayInfoToList(&raysListHead, column); if (foundTransparentWallV){ if (foundSolidWallV){ rayInfo_t * column = allocRayInfo(ra, distT2, r, 0, direction2 , htexture2); addRayInfoToList(&raysListHead, column); } else { rayInfo_t * column = allocRayInfo(ra, distT2, r, 0, direction, htexture2); addRayInfoToList(&raysListHead, column); } } // draw the ray in the minimap if (r == 0){ //printf("%d %d\n", (int)rx, (int)ry); ray1[0] = (int)rx; ray1[1] = (int)ry; //printf("ray1 %d %d\n", ray1[0], ray1[1]); //printf("ray2 %d %d\n", ray2[0], ray2[1]); } if (r == NB_RAYS - 1){ //printf("%d %d\n", (int)rx, (int)ry); ray2[0] = (int)rx; ray2[1] = (int)ry; printf("ray1 %d %d\n", ray1[0]/BLOCK_SIZE, ray1[1]/BLOCK_SIZE); printf("ray2 %d %d\n", ray2[0]/BLOCK_SIZE, ray2[1]/BLOCK_SIZE); } //printf("raylistlength %d\n", raysListLength); addRayToList(rx, ry); addRayToList(rx2, ry2); } } void drawEnnemy(){ float ennemyAngle = atan2((ennemy.y + ennemy.w/2) - (player.y + player.w/2) , (ennemy.x + ennemy.w/2) - (player.x + player.w/2)); if (ennemyAngle < 0) ennemyAngle += 2*pi; if (ennemyAngle > 2*pi) ennemyAngle -= 2*pi; float ennemyDistance = sqrt((ennemy.x - player.x)*(ennemy.x - player.x) + (ennemy.y - player.y)*(ennemy.y - player.y)) * BLOCK_SIZE; float ennemyBaseWidth = BLOCK_SIZE; float ennemyDistanceX = ennemyDistance * cos(ennemyAngle - player.angle) * BLOCK_SIZE; float ennemyDistanceY = ennemyDistance * fabs(sin(ennemyAngle - player.angle)) * BLOCK_SIZE; float scaledEnnemyWidth = ennemyBaseWidth / sqrt(3); int ennemyWidth = 50; int ennemyHeight = 200; //printf("%f %f\n", ennemyAngle, player.angle - (FOV_ANGLE)/2 * DR); //printf("%f\n", player.angle * RD); if (ennemyAngle >= player.angle - (FOV_ANGLE)/2 * DR && ennemyAngle <= player.angle + (FOV_ANGLE)/2 * DR){ rect.x = screenDimension.w/2 + (screenDimension.w * tan(ennemyAngle - player.angle)) * sqrt(3) * 0.5; rect.w = (ennemyWidth * screenDimension.w) / (ennemyDistance/BLOCK_SIZE); rect.h = (ennemyHeight * screenDimension.h)/(ennemyDistance/BLOCK_SIZE); rect.y = (screenDimension.h/2 + player.viewAngle) - rect.h/5; destRect.x = 0; destRect.y = 0; destRect.w = 64; destRect.h = 64; //printf("%d %d %d %d\n", rect.x, rect.y, rect.w, rect.h); SDL_RenderCopy(renderer, playerTexture, &destRect, &rect); } } void drawBall(){ float ballAngle = atan2((ball.y + ball.w/2) - (player.y + player.w/2) , (ball.x + ball.w/2) - (player.x + player.w/2)); if (ballAngle < 0) ballAngle += 2*pi; if (ballAngle > 2*pi) ballAngle -= 2*pi; float ballDistance = sqrt((ball.x - player.x)*(ball.x - player.x) + (ball.y - player.y)*(ball.y - player.y)) * BLOCK_SIZE; float ballBaseWidth = BLOCK_SIZE/2; float ballDistanceX = ballDistance * cos(ballAngle - player.angle) * BLOCK_SIZE; float ballDistanceY = ballDistance * fabs(sin(ballAngle - player.angle)) * BLOCK_SIZE; float scaledBallWidth = ballBaseWidth / sqrt(3); int ballWidth = 25; int ballHeight = 25; if (ballAngle >= player.angle - (FOV_ANGLE)/2 * DR && ballAngle <= player.angle + (FOV_ANGLE)/2 * DR){ rect.x = screenDimension.w/2 + (screenDimension.w * tan(ballAngle - player.angle)) * sqrt(3) * 0.5; rect.w = (ballWidth * screenDimension.w) / (ballDistance/BLOCK_SIZE); rect.h = (ballHeight * screenDimension.h)/(ballDistance/BLOCK_SIZE); rect.y = (screenDimension.h/2 + player.viewAngle) - rect.h/5; destRect.x = 0; destRect.y = 0; destRect.w = 64; destRect.h = 64; //printf("%d %d %d %d\n", rect.x, rect.y, rect.w, rect.h); SDL_RenderCopy(renderer, playerTexture, &destRect, &rect); } } void drawSkyAndGround(){ SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255); SDL_RenderFillRect(renderer, NULL); SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255); sky.x = 0; sky.y = 0; sky.w = screenDimension.w; sky.h = screenDimension.h/2 + player.viewAngle; SDL_RenderFillRect(renderer, &sky); SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); } void drawMap2D(int map[][MAP_WIDTH]){ int i, j; rect.w = CELL_SIZE; rect.h = CELL_SIZE; rect.x = 0; rect.y = 0; SDL_SetRenderDrawColor(renderer, 255, 255, 0, 255); for (i = 0; i < raysListLength; i++){ SDL_RenderDrawLine(renderer, player.x * CELL_SIZE / BLOCK_SIZE , player.y * CELL_SIZE / BLOCK_SIZE, rays[i][0] * CELL_SIZE / BLOCK_SIZE, rays[i][1] * CELL_SIZE / BLOCK_SIZE); } for (i = 0; i < MAP_HEIGHT; i++){ for (j = 0; j < MAP_WIDTH; j++){ switch (map[i][j]) { case 1: SDL_SetRenderDrawColor(renderer, 5, 255, 255, 255); SDL_RenderFillRect(renderer, &rect); break; case 2: SDL_SetRenderDrawColor(renderer, 255, 255, 255, 100); SDL_RenderFillRect(renderer, &rect); break; } if ((i == player.x/BLOCK_SIZE && j == player.y/BLOCK_SIZE) || (i == ennemy.x/BLOCK_SIZE && j == ennemy.y/BLOCK_SIZE)){ SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); SDL_RenderFillRect(renderer, &rect); } rect.x += CELL_SIZE; } rect.y += CELL_SIZE; rect.x = 0; } SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); } void drawString(char *str, int x, int y, int w, int h, int r, int g, int b, int a){ SDL_Color color = {r, g, b, a}; SDL_Surface *text = TTF_RenderText_Solid(RobotoFont, str, color); SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, text); rect.x = x; rect.y = y; rect.w = w; rect.h = h; SDL_RenderCopy(renderer, texture, NULL, &rect); SDL_FreeSurface(text); SDL_DestroyTexture(texture); } void drawFPS(){ char str[10]; sprintf(str, "%d", (int)fps); drawString(str, screenDimension.w - 50, 0, 50, 50, 255, 255, 255, 255); } void drawGame(){ SDL_RenderClear(renderer); drawSkyAndGround(); castRays(map); drawHorizentalRays(); drawEnnemy(); drawVerticalRays(); drawBall(); drawMap2D(map); drawFPS(); SDL_RenderPresent(renderer); } void mainLoop(){ createWindow(); initRays(); netTexture = loadTexture("Res/net.png"); crowdTexture = loadTexture("Res/crowd.png"); playerTexture = loadTexture("Res/player_sprite.png"); ray1 = malloc(sizeof(int) * 2); ray2 = malloc(sizeof(int) * 2); unsigned int a = SDL_GetTicks(); unsigned int b = SDL_GetTicks(); double delta = 0; pthread_t eventThread; if (pthread_create(&eventThread, NULL, EventLoop, NULL) != 0){ printf("Couldn't create thread."); exit(EXIT_FAILURE); } while (running){ a = SDL_GetTicks(); delta = (a - b); if (delta > 1000/FPS_TO_GET){ //printf("fps: %f\n", 1000/delta); fps = 1000/delta; b = a; switch (game_state){ case MENU: //Menu(); break; case GAME: drawGame(); break; } } else { // fait dormir le thread pour garder des ressources usleep(1000 * (1000/FPS_TO_GET - delta)); } } endSDL(); }