diff options
author | kartofen <mladenovnasko0@gmail.com> | 2023-04-09 23:36:55 +0300 |
---|---|---|
committer | kartofen <mladenovnasko0@gmail.com> | 2023-04-09 23:36:55 +0300 |
commit | 80ead50951c8b0d2c60c9fd57b8a4c943634b084 (patch) | |
tree | 635d8479b7e862d3cd7b3bc69b0cb64e31c38c2e | |
parent | fc027f7d214028086178a7328926c9b14ead464d (diff) |
things...
-rwxr-xr-x | build.sh | 2 | ||||
-rw-r--r-- | src/common.h | 24 | ||||
-rw-r--r-- | src/main.c | 65 | ||||
-rw-r--r-- | src/player.c | 9 | ||||
-rw-r--r-- | src/player.h | 4 | ||||
-rw-r--r-- | src/sector.c | 98 | ||||
-rw-r--r-- | src/sector.h | 6 |
7 files changed, 174 insertions, 34 deletions
@@ -7,7 +7,7 @@ NAME="main" DEBUG_FLAGS="-std=c99 -Wall -Wextra -g -pedantic -DDEBUG" # PROD_FLAGS="-std=c99 ???" SDL_FLAGS="`sdl2-config --cflags --libs`" -FLAGS="$DEBUG_FLAGS $SDL_FLAGS" +FLAGS="$DEBUG_FLAGS $SDL_FLAGS -lm" SRC="src" OBJ="obj" diff --git a/src/common.h b/src/common.h index d9a222f..4d0df29 100644 --- a/src/common.h +++ b/src/common.h @@ -1,14 +1,26 @@ #ifndef COMMON_H #define COMMON_H -#include <stdint.h> // for size_t +#include <stddef.h> // for size_t typedef unsigned int uint; -#define min(a, b) (((a) < (b)) ? (a) : (b)) -#define max(a, b) (((a) > (b)) ? (a) : (b)) -#define clamp(x, l, h) (min(max((x), (l)), (h))) -#define cross(x1, y1, x2, y2) ((x1)*(y2) - (x2)*(y1)) +#define min(a, b) (((a) < (b)) ? (a) : (b)) // choose smaller +#define max(a, b) (((a) > (b)) ? (a) : (b)) // choose bigger +#define clamp(x, l, h) (min(max((x), (l)), (h))) // clamp x between a range +#define vxs(x0,y0, x1,y1) ((x0)*(y1) - (x1)*(y0)) // vector cross product + +// Overlap: Determine whether the two number ranges overlap. +#define overlap(a0,a1,b0,b1) (min(a0,a1) <= max(b0,b1) && min(b0,b1) <= max(a0,a1)) +// IntersectBox: Determine whether two 2D-boxes intersect. +#define intersectbox(x0,y0, x1,y1, x2,y2, x3,y3) (overlap(x0,x1,x2,x3) && overlap(y0,y1,y2,y3)) +// PointSide: Determine which side of a line the point is on. Return value: <0, =0 or >0. +#define pointside(px,py, x0,y0, x1,y1) vxs((x1)-(x0), (y1)-(y0), (px)-(x0), (py)-(y0)) +// Intersect: Calculate the point of intersection between two lines. +#define intersect(x1,y1, x2,y2, x3,y3, x4,y4) ((struct xy) { \ + vxs(vxs(x1,y1, x2,y2), (x1)-(x2), vxs(x3,y3, x4,y4), (x3)-(x4)) / vxs((x1)-(x2), (y1)-(y2), (x3)-(x4), (y3)-(y4)), \ + vxs(vxs(x1,y1, x2,y2), (y1)-(y2), vxs(x3,y3, x4,y4), (y3)-(y4)) / vxs((x1)-(x2), (y1)-(y2), (x3)-(x4), (y3)-(y4)) }) + struct xy { float x, y; @@ -23,7 +35,7 @@ struct xyz { #define COLOR_RED 0xFF0000 #define COLOR_GREEN 0x00FF00 #define COLOR_BLUE 0x0000FF -#define COLOR_LIGHTWHITE 0xF5F5F5FF +#define COLOR_LIGHTWHITE 0xF5F5F5 #define color(col) (((col)>>16) & 0xFF), (((col)>>8) & 0xFF), ((col) & 0xFF) // macro wrapper for the sdl logging system @@ -30,17 +30,10 @@ int main(void) SDL_LogSetAllPriority(SDL_LOG_PRIORITY_ERROR); #endif - map_t m; - if(map_load(&m, "files/map_clear.txt")) - return 1; - map_print(&m); - map_unload(&m); - - return 0; - // ----------------- START SDL ----------------- // int ret = 1; SDL_Window *window = NULL; + map_t map = {0}; if(SDL_Init(SDL_INIT_VIDEO) != 0) { log_critical(LOG_VIDEO, "SDL_Init: %s", SDL_GetError()); @@ -62,14 +55,13 @@ int main(void) } // --------------------------------------------- // + if(map_load(&map, "files/map_clear.txt")) + return 1; bool quit = false; - while(!quit) { - // ----------------- GAME LOOP ----------------- // - for(int i = 0; i < SW; i++) - vline(i, 0, SH-1, COLOR_LIGHTWHITE); - // --------------------------------------------- // - + int wasd[4] = {0}; + while(!quit) + { SDL_Event event; while(SDL_PollEvent(&event)) { // ----------------- EVENTS ----------------- // @@ -77,13 +69,55 @@ int main(void) case SDL_QUIT: quit = true; break; + case SDL_KEYDOWN: + switch(event.key.keysym.sym) + { + case 'w': wasd[0] = 1; break; + case 'a': wasd[1] = 1; break; + case 's': wasd[2] = 1; break; + case 'd': wasd[3] = 1; break; + } + break; + case SDL_KEYUP: + switch(event.key.keysym.sym) + { + case 'w': wasd[0] = 0; break; + case 'a': wasd[1] = 0; break; + case 's': wasd[2] = 0; break; + case 'd': wasd[3] = 0; break; + } + break; default: - log_debug(LOG_APPLICATION, "event: %d", event.type); + // log_debug(LOG_APPLICATION, "event: %d", event.type); break; } // ------------------------------------------ // } + // ----------------- GAME LOOP ----------------- // + + int x,y; + SDL_GetRelativeMouseState(&x,&y); + map.player.angle += x * 0.03f; + + float move_vec[2] = {0.f, 0.f}; + if(wasd[0]) { move_vec[0] += map.player.anglecos*0.2f; move_vec[1] += map.player.anglesin*0.2f; } + if(wasd[2]) { move_vec[0] -= map.player.anglecos*0.2f; move_vec[1] -= map.player.anglesin*0.2f; } + if(wasd[1]) { move_vec[0] += map.player.anglesin*0.2f; move_vec[1] -= map.player.anglecos*0.2f; } + if(wasd[3]) { move_vec[0] -= map.player.anglesin*0.2f; move_vec[1] += map.player.anglecos*0.2f; } + int pushing = wasd[0] || wasd[1] || wasd[2] || wasd[3]; + float acceleration = pushing ? 0.4 : 0.2; + + map.player.pos.x += move_vec[0] * acceleration; + map.player.pos.y += move_vec[1] * acceleration; + + player_update(&map.player); + + for(int i = 0; i < SW-1; i++) + vline(i, 0, SH-1, COLOR_LIGHTWHITE); + map_draw(&map, SW, SH); + // --------------------------------------------- // + if(SDL_UpdateWindowSurface(window) != 0) { log_error(LOG_VIDEO, "SDL_UpdateWindowSurface: %s", SDL_GetError()); } @@ -91,6 +125,7 @@ int main(void) ret = 0; exit: + map_unload(&map); if(window != NULL) SDL_DestroyWindow(window); SDL_Quit(); return ret; diff --git a/src/player.c b/src/player.c index 4490f93..b94290d 100644 --- a/src/player.c +++ b/src/player.c @@ -1,3 +1,10 @@ +#include <math.h> #include "player.h" -// TODO: Implement the functions that manipulate a player +int player_update(player_t *player) +{ + player->anglesin = sinf(player->angle); + player->anglecos = cosf(player->angle); + + return 0; +} diff --git a/src/player.h b/src/player.h index 91a9d5e..ee5270b 100644 --- a/src/player.h +++ b/src/player.h @@ -6,9 +6,11 @@ typedef struct player { struct xyz pos, velocity; // vectors for the player float angle, anglesin, anglecos, yaw; // angle, and its sine and cosine - uint sector; // the sector that the player is in + size_t sector; // the sector that the player is in } player_t; +int player_update(player_t *player); + // TODO: Add functions to manipulate a player #endif diff --git a/src/sector.c b/src/sector.c index 3374995..5db3f3e 100644 --- a/src/sector.c +++ b/src/sector.c @@ -6,6 +6,88 @@ #define VERTS_CAP 512 #define SECTS_CAP 512 #define NUMS_CAP 512 +#define MAX_QUEUE 32 + +#define hfov (0.73f*SH) // Affects the horizontal field of vision +#define vfov (.2f*SH) // Affects the vertical field of vision + +void vline(int x, int y1, int y2, uint32_t col); + +int map_draw(map_t *map, uint SW, uint SH) +{ + int ytop[SW], ybottom[SW]; + for(uint i = 0; i < SW; i++) { + ytop[i] = 0; + ybottom[i] = SH-1; + } + + struct { int sx1, sx2 } now = {0, SW-1}; + struct sector *sect = &map->sectors[map->player.sector]; + + for(size_t i = 0; i < sect->nverts; i++) + { + map->player.pos.z = sect->floor + 6; //temp + + size_t s0 = sect->vertices[i], s1 = sect->vertices[i+1]; + + float vx1 = map->vertices[s0].x - map->player.pos.x, vy1 = map->vertices[s0].y - map->player.pos.y; + float vx2 = map->vertices[s1].x - map->player.pos.x, vy2 = map->vertices[s1].y - map->player.pos.y; + + float pcos = map->player.anglecos, psin = map->player.anglesin; + float tx1 = vx1 * psin - vy1 * pcos, tz1 = vx1 * pcos + vy1 * psin; + float tx2 = vx2 * psin - vy2 * pcos, tz2 = vx2 * pcos + vy2 * psin; + + if(tz1 <= 0 && tz2 <= 0) continue; + + // ??? magic + if(tz1 <= 0 || tz2 <= 0) + { + float nearz = 1e-4f, farz = 5, nearside = 1e-5f, farside = 20.f; + // Find an intersection between the wall and the approximate edges of player's view + struct xy i1 = intersect(tx1,tz1,tx2,tz2, -nearside,nearz, -farside,farz); + struct xy i2 = intersect(tx1,tz1,tx2,tz2, nearside,nearz, farside,farz); + if(tz1 < nearz) { if(i1.y > 0) { tx1 = i1.x; tz1 = i1.y; } else { tx1 = i2.x; tz1 = i2.y; } } + if(tz2 < nearz) { if(i1.y > 0) { tx2 = i1.x; tz2 = i1.y; } else { tx2 = i2.x; tz2 = i2.y; } } + } + + float xscale1 = hfov / tz1, yscale1 = vfov / tz1; int x1 = SW/2 - (int)(tx1 * xscale1); + float xscale2 = hfov / tz2, yscale2 = vfov / tz2; int x2 = SW/2 - (int)(tx2 * xscale2); + if(x1 >= x2 || x2 < now.sx1 || x1 > now.sx2) continue; // Only render if it's visible + /* Acquire the floor and ceiling heights, relative to where the player's view is */ + float yceil = sect->ceil - map->player.pos.z; + float yfloor = sect->floor - map->player.pos.z; + + size_t neighbor = sect->neighbors[i]; + + int y1a = SH/2 - (int)(yceil * yscale1), y1b = SH/2 - (int)(yfloor * yscale1); + int y2a = SH/2 - (int)(yceil * yscale2), y2b = SH/2 - (int)(yfloor * yscale2); + + int beginx = max(x1, now.sx1), endx = min(x2, now.sx2); + for(int x = beginx; x <= endx; ++x) + { + // int z = ((x - x1) * (tz2-tz1) / (x2-x1) + tz1) * 8; + /* Acquire the Y coordinates for our ceiling & floor for this X coordinate. Clamp them. */ + int ya = (x - x1) * (y2a-y1a) / (x2-x1) + y1a, cya = clamp(ya, ytop[x],ybottom[x]); // top + int yb = (x - x1) * (y2b-y1b) / (x2-x1) + y1b, cyb = clamp(yb, ytop[x],ybottom[x]); // bottom + + /* Render ceiling: everything above this sector's ceiling height. */ + vline(x, ytop[x], cya-1, COLOR_GREEN); + /* Render floor: everything below this sector's floor height. */ + vline(x, cyb+1, ybottom[x], COLOR_BLUE); + + if(neighbor == (size_t)-1) + { + // vline(x, cya, cyb, x==x1||x==x2 ? COLOR_LIGHTWHITE : COLOR_WHITE); + vline(x, cya, cyb, COLOR_WHITE); + } + else + { + vline(x, cya, cyb, COLOR_RED); + } + } + } + return 0; +} int map_load(map_t *map, char *filename) { @@ -53,7 +135,7 @@ int map_load(map_t *map, char *filename) sscanf(ptr += offset, "%f %f %n", §ors[sects].floor, §ors[sects].ceil, &offset); - int numbers[NUMS_CAP]; + size_t numbers[NUMS_CAP]; size_t nums = 0; while(sscanf(ptr += offset, "%s %n", word, &offset) != EOF) { if(nums >= NUMS_CAP) { @@ -79,7 +161,7 @@ int map_load(map_t *map, char *filename) sectors[sects++].nverts = nverts; break; case 'p': // player - sscanf(ptr += offset, "%f %f %f %d %n", &player.pos.x, &player.pos.y, &player.angle, (int *)&player.sector, &offset); + sscanf(ptr += offset, "%f %f %f %zu %n", &player.pos.x, &player.pos.y, &player.angle, &player.sector, &offset); break; } } @@ -128,23 +210,23 @@ int map_save(map_t *map, char *filename) void map_print(map_t *map) { - log("%ld %ld", map->nverts, map->nsects); + log("%zu %zu", map->nverts, map->nsects); for(size_t i = 0; i < map->nverts; i++) { - printf("v %ld {%.1f %.1f}\n", i, map->vertices[i].x, map->vertices[i].y); + printf("v %zu {%.1f %.1f}\n", i, map->vertices[i].x, map->vertices[i].y); } for(size_t i = 0; i < map->nsects; i++) { - printf("s %ld %.1f %.1f ", i, map->sectors[i].floor, map->sectors[i].ceil); + printf("s %zu %.1f %.1f ", i, map->sectors[i].floor, map->sectors[i].ceil); for(size_t j = 0; j < map->sectors[i].nverts + 1; j++) - printf("%d ", map->sectors[i].vertices[j]); + printf("%zu ", map->sectors[i].vertices[j]); printf(" "); for(size_t j = 0; j < map->sectors[i].nverts; j++) - printf("%d ", map->sectors[i].neighbors[j]); + printf("%zu ", map->sectors[i].neighbors[j]); printf("\n"); } - printf("p %.1f %.1f %.1f %d", map->player.pos.x, map->player.pos.y, map->player.angle, map->player.sector); + printf("p %.1f %.1f %.1f %zu", map->player.pos.x, map->player.pos.y, map->player.angle, map->player.sector); } diff --git a/src/sector.h b/src/sector.h index 20050f7..8315ee6 100644 --- a/src/sector.h +++ b/src/sector.h @@ -6,8 +6,8 @@ struct sector { float floor, ceil; // floor and ceiling heights - uint *vertices; // index of each vertex (vertices[nverts]) - uint *neighbors; // index of each neighboring sector (neighbors[nverts]) + size_t *vertices; // index of each vertex (vertices[nverts]) + size_t *neighbors; // index of each neighboring sector (neighbors[nverts]) size_t nverts; // number of vertices defining the sector }; @@ -19,10 +19,12 @@ typedef struct { player_t player; // the player (should be an array in the future) } map_t; +int map_draw(map_t *map, uint SW, uint SH); int map_load(map_t *map, char *filename); void map_unload(map_t *map); void map_print(map_t *map); int map_save(map_t *map, char *filename); + #endif |