diff options
| -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 | 
