summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkartofen <mladenovnasko0@gmail.com>2023-04-09 23:36:55 +0300
committerkartofen <mladenovnasko0@gmail.com>2023-04-09 23:36:55 +0300
commit80ead50951c8b0d2c60c9fd57b8a4c943634b084 (patch)
tree635d8479b7e862d3cd7b3bc69b0cb64e31c38c2e
parentfc027f7d214028086178a7328926c9b14ead464d (diff)
things...
-rwxr-xr-xbuild.sh2
-rw-r--r--src/common.h24
-rw-r--r--src/main.c65
-rw-r--r--src/player.c9
-rw-r--r--src/player.h4
-rw-r--r--src/sector.c98
-rw-r--r--src/sector.h6
7 files changed, 174 insertions, 34 deletions
diff --git a/build.sh b/build.sh
index 6ddf9a4..8405053 100755
--- a/build.sh
+++ b/build.sh
@@ -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
diff --git a/src/main.c b/src/main.c
index 8b5aa40..108649d 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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", &sectors[sects].floor, &sectors[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