BackRoomsMaker/src/display.c

304 lines
12 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <stdbool.h>
#include <ncurses.h>
#include <unistd.h>
#include <termios.h>
#include <limits.h>
#include <time.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include "hash.h"
#include "structure.h"
#include "base.h"
#include "generation.h"
#include "display.h"
void updateRenderer(SDL_Renderer* renderer) {
//printf("E");
SDL_RenderPresent(renderer);
}
void resetRenderer(SDL_Renderer* renderer) {
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
}
void drawRectToRenderer(SDL_Renderer* renderer, SDL_Rect* rect, int R, int G, int B, int A) {
SDL_SetRenderDrawColor(renderer, R, G, B, A);
SDL_RenderFillRect(renderer, rect);
}
void placeRectToRenderer(SDL_Renderer* renderer, int X, int Y, int W, int H, int R, int G, int B, int A) {
SDL_Rect rect;
rect.x = X;
rect.y = Y;
rect.w = W;
rect.h = H;
SDL_SetRenderDrawColor(renderer, R, G, B, A);
SDL_RenderFillRect(renderer, &rect);
}
void drawLineWithThicc(SDL_Renderer* renderer, int width, int x1, int x2, int y1, int y2, int R, int G, int B, int A) {
// draws line with width (native SDL cannot do that)
double theta = 0.0;
double seglen = distance_pt(x1, x2, y1, y2);
while(theta < 1.0) {
placeRectToRenderer(renderer, convex_seg(x1, x2, theta)-width/2, convex_seg(y1, y2, theta)-width/2, width, width, R, G, B, A);
theta += 1 / seglen;
}
}
void drawLineWithThiccGradient(SDL_Renderer* renderer, int start_width, int end_width, int x1, int x2, int y1, int y2, int R, int G, int B, int A) {
// draws line with width ;
// width goes from start_width to end_with in a linear way
double theta = 0.0;
double seglen = distance_pt(x1, x2, y1, y2);
while(theta < 1.0) {
int width = convex_seg(start_width, end_width, theta) ;
placeRectToRenderer(renderer, convex_seg(x1, x2, theta)-width/2, convex_seg(y1, y2, theta)-width/2, width, width, R, G, B, A);
theta += 1 / seglen;
}
}
void drawDigitToRenderer(SDL_Renderer* renderer, imgs data, int digit, int X, int Y, int W, int H) {
if(digit == -727) {
SDL_Rect rect;
rect.x = X;
rect.y = Y;
rect.w = W;
rect.h = H;
SDL_Texture* texture = data.arr[10];
SDL_RenderCopy(renderer, texture, NULL, &rect);
} else if (!(0 <= digit && digit <= 9)) {
fprintf(stderr, "Illegal digit : '%d'.\n", digit);
exit(1);
} else {
SDL_Rect rect;
rect.x = X;
rect.y = Y;
rect.w = W;
rect.h = H;
SDL_Texture* texture = data.arr[digit];
SDL_RenderCopy(renderer, texture, NULL, &rect);
}
}
void drawCharToRenderer(SDL_Renderer* renderer, imgs data, char c, int X, int Y, int W, int H) {
if ((int)c >= 97 && (int)c <= 122) {
SDL_Rect rect;
rect.x = X;
rect.y = Y;
rect.w = W;
rect.h = H;
SDL_Texture* texture = data.arr[(int)c - 97];
SDL_RenderCopy(renderer, texture, NULL, &rect);
}
}
void drawNumberToRenderer(SDL_Renderer* renderer, imgs data, int n, int X, int Y, int W, int H, int Woffset) {
if(n == 0) {
drawDigitToRenderer(renderer, data, 0, X + W, Y, W, H);
} else if(n > 0) {
int toDraw = 0, remaining = n, nIter = ln_baseN(n, 10);
while(nIter != 0) {
toDraw = remaining%10;
remaining = remaining / 10;
drawDigitToRenderer(renderer, data, toDraw, X + (W-Woffset)*nIter, Y, W, H);
nIter--;
}
} else {
int toDraw = 0, remaining = -n, nIter = ln_baseN(-n, 10);
drawDigitToRenderer(renderer, data, -727, X, Y, W, H);
while(nIter != 0) {
toDraw = remaining%10;
remaining = remaining / 10;
drawDigitToRenderer(renderer, data, toDraw, X + (W-Woffset)*nIter, Y, W, H);
nIter--;
}
}
}
void drawStringToRenderer(SDL_Renderer* renderer, imgs data, char* s, int X, int Y, int W, int H) {
int k = 0 ;
while(s[k] != '\0') {
drawCharToRenderer(renderer, data, s[k], X + W*k, Y, W, H);
k += 1;
}
}
void rescale(int* xm, int* xM, int* ym, int* yM, double scale) {
*xm = (int)((*xm - __width__/2) * scale + __width__/2) ;
*xM = (int)((*xM - __width__/2) * scale + __width__/2) ;
*ym = (int)((*ym - __height__/2) * scale + __height__/2) ;
*yM = (int)((*yM - __height__/2) * scale + __height__/2) ;
}
bool isOnLeft(chunk* ch, int x, int y) {
return (x == 0 || unpack_coord(ch->chdata.lines, x-1, y));
}
bool isOnRight(chunk* ch, int x, int y) {
return (x == 7 || unpack_coord(ch->chdata.lines, x+1, y));
}
bool isOnTop(chunk* ch, int x, int y) {
return (y == 0 || unpack_coord(ch->chdata.lines, x, y-1));
}
bool isOnBottom(chunk* ch, int x, int y) {
return (y == 7 || unpack_coord(ch->chdata.lines, x, y+1));
}
bool isPtInPoly(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int xp, int yp) {
// (x2 - x1) * (yp - y1) - (xp - x1) * (y2 - y1) ;
int v1 = (x2 - x1) * (yp - y1) - (xp - x1) * (y2 - y1) ;
int v2 = (x3 - x2) * (yp - y2) - (xp - x2) * (y3 - y2) ;
int v3 = (x4 - x3) * (yp - y3) - (xp - x3) * (y4 - y3) ;
int v4 = (x1 - x4) * (yp - y4) - (xp - x4) * (y1 - y4) ;
return (sign(v1) == sign(v2) && sign(v2) == sign(v3) && sign(v3) == sign(v4));
}
static int total ;
void fillQuadPoly(SDL_Renderer* renderer, int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) {
int ymin = min(min(y1, y2), min(y3, y4));
int ymax = max(max(y1, y2), max(y3, y4));
int xmin = min(min(x1, x2), min(x3, x4));
int xmax = max(max(x1, x2), max(x3, x4));
for(int h = ymin; h <= ymax; h++) {
for(int w = xmin; w <= xmax; w++) {
if(isPtInPoly(x1, y1, x2, y2, x3, y3, x4, y4, w, h)) {
SDL_RenderDrawPoint(renderer, w, h);
}
}
};
/*double step = max_db(distance_pt(x1, y1, x2, y2), distance_pt(x3, y3, x4, y4));
double theta = 0.0 ;
while(theta <= 1.0) {
total += 1 ;
drawLineWithThicc(renderer, 2, convex_seg(x1, x2, theta), convex_seg(x4, x3, theta), convex_seg(y1, y2, theta), convex_seg(y4, y3, theta), 255, 192, 255, SDL_ALPHA_OPAQUE);
theta += 1.0 / step;
}*/
/*total += (ymax-ymin)*(xmax-xmin) ;
printf("T = %d\n", total);*/
drawLineWithThicc(renderer, 2, x1, x2, y1, y2, 32, 32, 32, SDL_ALPHA_OPAQUE);
drawLineWithThicc(renderer, 2, x2, x3, y2, y3, 32, 32, 32, SDL_ALPHA_OPAQUE);
drawLineWithThicc(renderer, 2, x3, x4, y3, y4, 32, 32, 32, SDL_ALPHA_OPAQUE);
drawLineWithThicc(renderer, 2, x4, x1, y4, y1, 32, 32, 32, SDL_ALPHA_OPAQUE);
}
void drawChunkToRenderer(SDL_Renderer* renderer, chunk* ch, int xmin, int xmax, int ymin, int ymax, bool period) {
if(ch->draw_id != draw_par || !period) {
ch->draw_id = draw_par ;
for(int i = 0; i < 8; i++) {
uint8_t cur = ch->chdata.lines[i] ;
for(int j = 0; j < 8; j++) {
int cux = 50*(8*ch->chx + j);
int cuy = 50*(8*ch->chy + i);
int cux2 = 50*(8*ch->chx + j+1);
int cuy2 = 50*(8*ch->chy + i+1);
if(true) {
if(cur%2 == 1) {
int nxmin = to_int((to_double(cux) - to_double(xmin)) * to_double(__width__)) / (to_double(xmax) - to_double(xmin)) ;
int nymin = to_int((to_double(cuy) - to_double(ymin)) * to_double(__height__)) / (to_double(ymax) - to_double(ymin)) ;
int nxmax = to_int((to_double(cux2) - to_double(xmin)) * to_double(__width__)) / (to_double(xmax) - to_double(xmin)) ;
int nymax = to_int((to_double(cuy2) - to_double(ymin)) * to_double(__height__)) / (to_double(ymax) - to_double(ymin)) ;
uint8_t R = 255 - 63 * ((abs(ch->chx) + abs(ch->chy))%2 == 0) ;
uint8_t G = 255 ;
uint8_t B = 255 - 63 * ((abs(ch->chx) + abs(ch->chy))%2 == 1) ;
int sxmin = nxmin ;
int sxmax = nxmax ;
int symin = nymin ;
int symax = nymax ;
rescale(&nxmin, &nxmax, &nymin, &nymax, 1.5);
if(period) {
if(!isOnLeft(ch, i, j) && (8*ch->chy + i) >= (8*player_cy + player_y)) { // North
SDL_SetRenderDrawColor(renderer, R/2, G/2, B/2, SDL_ALPHA_OPAQUE);
fillQuadPoly(renderer, nxmin, nymin, sxmin, symin, sxmax, symin, nxmax, nymin);
}
if(!isOnBottom(ch, i, j) && (8*ch->chx + j) <= (8*player_cx + player_x)) { // West
SDL_SetRenderDrawColor(renderer, R/2, G/2, B/2, SDL_ALPHA_OPAQUE);
fillQuadPoly(renderer, nxmax, nymax, sxmax, symax, sxmax, symin, nxmax, nymin);
}
if(!isOnRight(ch, i, j) && (8*ch->chy + i) <= (8*player_cy + player_y)) { // South
SDL_SetRenderDrawColor(renderer, R/2, G/2, B/2, SDL_ALPHA_OPAQUE);
fillQuadPoly(renderer, nxmax, nymax, sxmax, symax, sxmin, symax, nxmin, nymax);
}
if(!isOnTop(ch, i, j) && (8*ch->chx + j) >= (8*player_cx + player_x)) { // East
SDL_SetRenderDrawColor(renderer, R/2, G/2, B/2, SDL_ALPHA_OPAQUE);
fillQuadPoly(renderer, nxmin, nymin, sxmin, symin, sxmin, symax, nxmin, nymax);
}
} else {
SDL_SetRenderDrawColor(renderer, R, G, B, SDL_ALPHA_OPAQUE);
placeRectToRenderer(renderer, nxmin, nymin, nxmax - nxmin, nymax - nymin, 32, 32, 32, SDL_ALPHA_OPAQUE);
placeRectToRenderer(renderer, nxmin+1, nymin+1, nxmax - nxmin -2, nymax - nymin -2, R, G, B, SDL_ALPHA_OPAQUE);
}
};
cur = cur / 2 ;
}
}
}
}
}
void drawHashToRenderer(SDL_Renderer* renderer, int chx, int chy, int xmin, int xmax, int ymin, int ymax, int distx, int disty) {
if(distx < render_distance && disty < render_distance) {
chunk* todraw = gridGet(map, chx, chy) ;
if(todraw == NULL) {
fprintf(stderr, "NO (%d, %d)\n", chx, chy);
exit(1);
};
if(distx != render_distance -1 && !gridMem(map, chx+1, chy)) {
generate_chunk_all(chx+1, chy);
};
if(distx != render_distance -1 && !gridMem(map, chx-1, chy)) {
generate_chunk_all(chx-1, chy);
};
if(disty != render_distance -1 && !gridMem(map, chx, chy+1)) {
generate_chunk_all(chx, chy+1);
};
if(disty != render_distance -1 && !gridMem(map, chx, chy-1)) {
generate_chunk_all(chx, chy-1);
};
drawHashToRenderer(renderer, chx+1, chy, xmin, xmax, ymin, ymax, distx+1, disty);
drawHashToRenderer(renderer, chx-1, chy, xmin, xmax, ymin, ymax, distx+1, disty);
drawHashToRenderer(renderer, chx, chy+1, xmin, xmax, ymin, ymax, distx, disty+1);
drawHashToRenderer(renderer, chx, chy-1, xmin, xmax, ymin, ymax, distx, disty+1);
drawChunkToRenderer(renderer, todraw, xmin, xmax, ymin, ymax, false);
}
}
void drawMapToRenderer(SDL_Renderer* renderer, int xmin, int xmax, int ymin, int ymax) {
drawHashToRenderer(renderer, player_cx, player_cy, xmin, xmax, ymin, ymax, 0, 0);
placeRectToRenderer(renderer, __width__ /2 - 5*zoom/100, __height__ /2 - 5*zoom/100, 10*zoom/100, 10*zoom/100, 255, 255, 32, SDL_ALPHA_OPAQUE);
}
void drawMapToRendererV2(SDL_Renderer* renderer, int xmin, int xmax, int ymin, int ymax) {
for(int i = 0; i < (2*render_distance+1)*(2*render_distance+1); i++) {
if(!gridMem(map, player_cx+sorted_x[i], player_cy + sorted_y[i])) {
generate_chunk_all(player_cx+sorted_x[i], player_cy + sorted_y[i]);
}
chunk* todraw = gridGet(map, player_cx+sorted_x[i], player_cy + sorted_y[i]) ;
drawChunkToRenderer(renderer, todraw, xmin, xmax, ymin, ymax, true);
drawChunkToRenderer(renderer, todraw, xmin, xmax, ymin, ymax, false);
}
placeRectToRenderer(renderer, __width__ /2 - 5*zoom/100, __height__ /2 - 5*zoom/100, 10*zoom/100, 10*zoom/100, 255, 255, 32, SDL_ALPHA_OPAQUE);
}