diff --git a/apps/demos/scenery/scenes/ingame.c b/apps/demos/scenery/scenes/ingame.c index 3c20c57..a78e635 100644 --- a/apps/demos/scenery/scenes/ingame.c +++ b/apps/demos/scenery/scenes/ingame.c @@ -12,10 +12,13 @@ #define TERRAIN_FREQUENCY 0.15f -#define TERRAIN_DISTANCE 128 +#define TERRAIN_RADIUS 128 +#define GRASS_RADIUS 16 +#define TERRAIN_DISTANCE (TERRAIN_RADIUS * 2) #define HALF_TERRAIN_DISTANCE ((float)TERRAIN_DISTANCE / 2) #define PLAYER_HEIGHT 0.6f +/* TODO: pregenerate grid of levels of detail */ static float heightmap[TERRAIN_DISTANCE][TERRAIN_DISTANCE]; @@ -23,7 +26,7 @@ static void process_fly_mode(State *state) { SceneIngame *scn = (SceneIngame *)state->scene; DrawCameraFromPrincipalAxesResult dir_and_up = - draw_camera_from_principal_axes(scn->pos, scn->roll, scn->pitch, scn->yaw, (float)M_PI_2 * 0.8f, 1); + draw_camera_from_principal_axes(scn->pos, scn->roll, scn->pitch, scn->yaw, (float)M_PI_2 * 0.8f, 1, TERRAIN_RADIUS * M_SQRT2f); const Vec3 right = m_vec_norm(m_vec_cross(dir_and_up.direction, dir_and_up.up)); const float speed = 0.04f; /* TODO: put this in a better place */ @@ -80,7 +83,7 @@ static void process_ground_mode(State *state) { SceneIngame *scn = (SceneIngame *)state->scene; DrawCameraFromPrincipalAxesResult dir_and_up = - draw_camera_from_principal_axes(scn->pos, scn->roll, scn->pitch, scn->yaw, (float)M_PI_2 * 0.8f, 1); + draw_camera_from_principal_axes(scn->pos, scn->roll, scn->pitch, scn->yaw, (float)M_PI_2 * 0.8f, 1, TERRAIN_RADIUS * M_SQRT2f); dir_and_up.direction.y = 0; dir_and_up.direction = vec3_norm(dir_and_up.direction); @@ -134,7 +137,7 @@ static void generate_terrain(SceneIngame *scn) { float y = floorf(scn->pos.z - HALF_TERRAIN_DISTANCE + (float)ly); float height = stb_perlin_noise3((float)x * TERRAIN_FREQUENCY, (float)y * TERRAIN_FREQUENCY, 0, 0, 0, 0) * 3 - 1; - height += stb_perlin_noise3((float)x * TERRAIN_FREQUENCY / 10, (float)y * TERRAIN_FREQUENCY / 10, 0, 0, 0, 0) * 10 - 1; + height += stb_perlin_noise3((float)x * TERRAIN_FREQUENCY / 10, (float)y * TERRAIN_FREQUENCY / 10, 0, 0, 0, 0) * 20 - 1; heightmap[lx][ly] = height; } @@ -142,9 +145,23 @@ static void generate_terrain(SceneIngame *scn) { } +static int32_t ceil_sqrt(int32_t const n) { + int32_t res = 1; + while(res * res < n) + res++; + return res; +} + + static void draw_terrain(SceneIngame *scn) { - for (int ly = TERRAIN_DISTANCE - 1; ly > 0; ly--) { - for (int lx = 0; lx < TERRAIN_DISTANCE - 1; lx++) { + /* draw terrain in circle */ + int32_t const rsi = (int32_t)TERRAIN_RADIUS * (int32_t)TERRAIN_RADIUS; + for (int32_t iy = -(int32_t)TERRAIN_RADIUS; iy <= (int32_t)TERRAIN_RADIUS - 1; ++iy) { + int32_t const dx = ceil_sqrt(rsi - (iy + (iy <= 0)) * (iy + (iy <= 0))); + for (int32_t ix = -dx; ix < dx; ++ix) { + int32_t lx = ix + TERRAIN_RADIUS; + int32_t ly = iy + TERRAIN_RADIUS; + int32_t x = (int32_t)(floorf(scn->pos.x - HALF_TERRAIN_DISTANCE + (float)lx)); int32_t y = (int32_t)(floorf(scn->pos.z - HALF_TERRAIN_DISTANCE + (float)ly)); @@ -160,8 +177,21 @@ static void draw_terrain(SceneIngame *scn) { (Vec3){ (float)x, d3, (float)y - 1 }, (Rect){ .w = 128, .h = 128 }, (Color){255, 255, 255, 255}); + } + } + + int32_t const rsi_g = (int32_t)GRASS_RADIUS * (int32_t)GRASS_RADIUS; + for (int32_t iy = -(int32_t)GRASS_RADIUS; iy <= (int32_t)GRASS_RADIUS - 1; ++iy) { + int32_t const dx = ceil_sqrt(rsi_g - (iy + (iy <= 0)) * (iy + (iy <= 0))); + for (int32_t ix = -dx; ix < dx; ++ix) { + int32_t lx = ix + TERRAIN_RADIUS; + int32_t ly = iy + TERRAIN_RADIUS; + + int32_t x = (int32_t)(floorf(scn->pos.x - HALF_TERRAIN_DISTANCE + (float)lx)); + int32_t y = (int32_t)(floorf(scn->pos.z - HALF_TERRAIN_DISTANCE + (float)ly)); + + float d0 = heightmap[lx][ly]; - /* TODO: only draw upclose */ draw_billboard("/assets/grasses/10.png", (Vec3){ (float)x, d0 + 0.15f, (float)y }, (Vec2){0.3f, 0.3f}, @@ -216,7 +246,7 @@ static void ingame_tick(State *state) { draw_skybox("/assets/miramar/miramar_*.tga"); ctx.fog_color = (Color){ 140, 147, 160, 255 }; - ctx.fog_density = 0.03f; + ctx.fog_density = 0.02f; } diff --git a/include/twn_draw.h b/include/twn_draw.h index 487d20e..078d339 100644 --- a/include/twn_draw.h +++ b/include/twn_draw.h @@ -86,11 +86,12 @@ TWN_API void draw_camera_2d(Vec2 position, /* optional, default: (0, 0) */ /* sets a perspective 3d camera to be used for all 3d commands */ /* fov = 0 corresponds to orthographic projection */ -TWN_API void draw_camera(Vec3 position, +TWN_API void draw_camera(Vec3 position, /* optional, default: (0, 0, 0) */ Vec3 direction, /* optional, default: (0, 0, -1) */ Vec3 up, /* optional, default: (0, 1, 0) */ float fov, /* optional, default: PI / 6 * 3 (90 degrees) */ - float zoom); /* optional, default: 1 */ + float zoom, /* optional, default: 1 */ + float draw_distance); /* optional, default: 100 */ /* same as draw_camera(), but with first person controller in mind */ /* direction and up vectors are inferred from roll, pitch and yaw parameters (in radians) */ @@ -100,12 +101,13 @@ typedef struct DrawCameraFromPrincipalAxesResult { Vec3 up; } DrawCameraFromPrincipalAxesResult; TWN_API DrawCameraFromPrincipalAxesResult -draw_camera_from_principal_axes(Vec3 position, - float roll, /* optional, default: 0 */ - float pitch, /* optional, default: 0 */ - float yaw, /* optional, default: 0 */ - float fov, /* optional, default: PI / 6 * 3 (90 degrees) */ - float zoom); /* optional, default: 1 */ +draw_camera_from_principal_axes(Vec3 position, /* optional, default: (0, 0, 0) */ + float roll, /* optional, default: 0 */ + float pitch, /* optional, default: 0 */ + float yaw, /* optional, default: 0 */ + float fov, /* optional, default: PI / 6 * 3 (90 degrees) */ + float zoom, /* optional, default: 1 */ + float draw_distance); /* optional, default: 100 */ /* expects '*' masks that will be expanded to 6 names: 'up', 'down', 'east', 'west', 'north' and 'south' */ TWN_API void draw_skybox(const char *textures); diff --git a/share/twn_api.json b/share/twn_api.json index 31a9986..495a95f 100644 --- a/share/twn_api.json +++ b/share/twn_api.json @@ -207,11 +207,12 @@ "symbol": "camera", "header": "twn_draw.h", "params": [ - { "name": "position", "type": "Vec3" }, + { "name": "position", "type": "Vec3", "default": { "x": 0, "y": 0, "z": 0 } }, { "name": "direction", "type": "Vec3", "default": { "x": 0, "y": 0, "z": -1 } }, { "name": "up", "type": "Vec3", "default": { "x": 0, "y": 1, "z": 0 } }, { "name": "fov", "type": "float", "default": 1.57079632679 }, - { "name": "zoom", "type": "float", "default": 1 } + { "name": "zoom", "type": "float", "default": 1 }, + { "name": "draw_distance", "type": "float", "default": 100 } ] }, @@ -220,12 +221,13 @@ "symbol": "camera_from_principal_axes", "header": "twn_draw.h", "params": [ - { "name": "position", "type": "Vec3" }, + { "name": "position", "type": "Vec3", "default": { "x": 0, "y": 0, "z": 0 } }, { "name": "roll", "type": "float", "default": 0 }, { "name": "pitch", "type": "float", "default": 0 }, { "name": "yaw", "type": "float", "default": 0 }, { "name": "fov", "type": "float", "default": 1.57079632679 }, - { "name": "zoom", "type": "float", "default": 1 } + { "name": "zoom", "type": "float", "default": 1 }, + { "name": "draw_distance", "type": "float", "default": 100 } ], "return": { "fields": [ diff --git a/src/rendering/twn_draw.c b/src/rendering/twn_draw.c index ac7b450..c13d738 100644 --- a/src/rendering/twn_draw.c +++ b/src/rendering/twn_draw.c @@ -20,6 +20,7 @@ DeferredCommand *deferred_commands; /* TODO: with buffered render, don't we use camera of wrong frame right now ? */ Matrix4 camera_projection_matrix; Matrix4 camera_look_at_matrix; +float camera_far_z; float camera_2d_rotation; Vec2 camera_2d_position; @@ -36,7 +37,7 @@ static void reset_camera_2d(void) { void render_clear(void) { - draw_camera((Vec3){0, 0, 0}, (Vec3){0, 0, 1}, (Vec3){0, 1, 0}, 1.57079632679f, 1); + draw_camera((Vec3){0, 0, 0}, (Vec3){0, 0, 1}, (Vec3){0, 1, 0}, 1.57079632679f, 1, 100); reset_camera_2d(); text_cache_reset_arena(&ctx.text_cache); @@ -423,7 +424,7 @@ TWN_API void draw_camera_2d(Vec2 position, } /* TODO: check for NaNs and alike */ -void draw_camera(Vec3 position, Vec3 direction, Vec3 up, float fov, float zoom) { +void draw_camera(Vec3 position, Vec3 direction, Vec3 up, float fov, float zoom, float draw_distance) { bool const orthographic = fabsf(0.0f - fov) < 0.00001f; if (!orthographic && fov >= (float)(M_PI)) log_warn("Invalid fov given (%f)", (double)fov); @@ -437,6 +438,7 @@ void draw_camera(Vec3 position, Vec3 direction, Vec3 up, float fov, float zoom) (Vec2){ 1/-zoom, 1/zoom }, (Vec2){ 1/zoom, 1/-zoom } }, + .far_z = draw_distance }; if (!orthographic) @@ -444,6 +446,8 @@ void draw_camera(Vec3 position, Vec3 direction, Vec3 up, float fov, float zoom) else camera_projection_matrix = camera_orthographic(&camera); + camera_far_z = draw_distance; + camera_look_at_matrix = camera_look_at(&camera); } @@ -455,7 +459,8 @@ DrawCameraFromPrincipalAxesResult draw_camera_from_principal_axes(Vec3 position, float pitch, float yaw, float fov, - float zoom) + float zoom, + float draw_distance) { bool const orthographic = fabsf(0.0f - fov) < 0.00001f; if (!orthographic && fov >= (float)(M_PI)) @@ -476,7 +481,7 @@ DrawCameraFromPrincipalAxesResult draw_camera_from_principal_axes(Vec3 position, Vec3 const up = (Vec3){0, 1, 0}; - draw_camera(position, direction, up, fov, zoom); + draw_camera(position, direction, up, fov, zoom, draw_distance); return (DrawCameraFromPrincipalAxesResult) { .direction = direction, diff --git a/src/rendering/twn_draw_c.h b/src/rendering/twn_draw_c.h index 63732e4..f2828f0 100644 --- a/src/rendering/twn_draw_c.h +++ b/src/rendering/twn_draw_c.h @@ -16,6 +16,7 @@ extern Matrix4 camera_projection_matrix; extern Matrix4 camera_look_at_matrix; +extern float camera_far_z; extern float camera_2d_rotation; extern Vec2 camera_2d_position; diff --git a/src/rendering/twn_gl_15_rendering.c b/src/rendering/twn_gl_15_rendering.c index 0b7adbc..0b38856 100644 --- a/src/rendering/twn_gl_15_rendering.c +++ b/src/rendering/twn_gl_15_rendering.c @@ -441,66 +441,68 @@ void finally_render_skybox(DeferredCommandDrawSkybox command) { glEnable(GL_DEPTH_CLAMP); #endif + float const d = camera_far_z / sqrtf(3); + glBegin(GL_QUADS); { /* up */ - glTexCoord3f(50.f, 50.f, 50.f); - glVertex3f(50.f, 50.f, 50.f); - glTexCoord3f(-50.f, 50.f, 50.f); - glVertex3f(-50.f, 50.f, 50.f); - glTexCoord3f(-50.f, 50.f, -50.f); - glVertex3f(-50.f, 50.f, -50.f); - glTexCoord3f(50.f, 50.f, -50.f); - glVertex3f(50.f, 50.f, -50.f); + glTexCoord3f(d, d, d); + glVertex3f(d, d, d); + glTexCoord3f(-d, d, d); + glVertex3f(-d, d, d); + glTexCoord3f(-d, d, -d); + glVertex3f(-d, d, -d); + glTexCoord3f(d, d, -d); + glVertex3f(d, d, -d); /* down */ - glTexCoord3f(50.f, -50.f, 50.f); - glVertex3f(50.f, -50.f, 50.f); - glTexCoord3f(50.f, -50.f, -50.f); - glVertex3f(50.f, -50.f, -50.f); - glTexCoord3f(-50.f, -50.f, -50.f); - glVertex3f(-50.f, -50.f, -50.f); - glTexCoord3f(-50.f, -50.f, 50.f); - glVertex3f(-50.f, -50.f, 50.f); + glTexCoord3f(d, -d, d); + glVertex3f(d, -d, d); + glTexCoord3f(d, -d, -d); + glVertex3f(d, -d, -d); + glTexCoord3f(-d, -d, -d); + glVertex3f(-d, -d, -d); + glTexCoord3f(-d, -d, d); + glVertex3f(-d, -d, d); /* east */ - glTexCoord3f(50.f, -50.f, 50.f); - glVertex3f(50.f, -50.f, 50.f); - glTexCoord3f(50.f, 50.f, 50.f); - glVertex3f(50.f, 50.f, 50.f); - glTexCoord3f(50.f, 50.f, -50.f); - glVertex3f(50.f, 50.f, -50.f); - glTexCoord3f(50.f, -50.f, -50.f); - glVertex3f(50.f, -50.f, -50.f); + glTexCoord3f(d, -d, d); + glVertex3f(d, -d, d); + glTexCoord3f(d, d, d); + glVertex3f(d, d, d); + glTexCoord3f(d, d, -d); + glVertex3f(d, d, -d); + glTexCoord3f(d, -d, -d); + glVertex3f(d, -d, -d); /* west */ - glTexCoord3f(-50.f, -50.f, 50.f); - glVertex3f(-50.f, -50.f, 50.f); - glTexCoord3f(-50.f, -50.f, -50.f); - glVertex3f(-50.f, -50.f, -50.f); - glTexCoord3f(-50.f, 50.f, -50.f); - glVertex3f(-50.f, 50.f, -50.f); - glTexCoord3f(-50.f, 50.f, 50.f); - glVertex3f(-50.f, 50.f, 50.f); + glTexCoord3f(-d, -d, d); + glVertex3f(-d, -d, d); + glTexCoord3f(-d, -d, -d); + glVertex3f(-d, -d, -d); + glTexCoord3f(-d, d, -d); + glVertex3f(-d, d, -d); + glTexCoord3f(-d, d, d); + glVertex3f(-d, d, d); /* north */ - glTexCoord3f(-50.f, -50.f, 50.f); - glVertex3f(-50.f, -50.f, 50.f); - glTexCoord3f(-50.f, 50.f, 50.f); - glVertex3f(-50.f, 50.f, 50.f); - glTexCoord3f(50.f, 50.f, 50.f); - glVertex3f(50.f, 50.f, 50.f); - glTexCoord3f(50.f, -50.f, 50.f); - glVertex3f(50.f, -50.f, 50.f); + glTexCoord3f(-d, -d, d); + glVertex3f(-d, -d, d); + glTexCoord3f(-d, d, d); + glVertex3f(-d, d, d); + glTexCoord3f(d, d, d); + glVertex3f(d, d, d); + glTexCoord3f(d, -d, d); + glVertex3f(d, -d, d); /* south */ - glTexCoord3f(-50.f, -50.f, -50.f); - glVertex3f(-50.f, -50.f, -50.f); - glTexCoord3f(50.f, -50.f, -50.f); - glVertex3f(50.f, -50.f, -50.f); - glTexCoord3f(50.f, 50.f, -50.f); - glVertex3f(50.f, 50.f, -50.f); - glTexCoord3f(-50.f, 50.f, -50.f); - glVertex3f(-50.f, 50.f, -50.f); + glTexCoord3f(-d, -d, -d); + glVertex3f(-d, -d, -d); + glTexCoord3f(d, -d, -d); + glVertex3f(d, -d, -d); + glTexCoord3f(d, d, -d); + glVertex3f(d, d, -d); + glTexCoord3f(-d, d, -d); + glVertex3f(-d, d, -d); } glEnd(); #ifndef __EMSCRIPTEN__ diff --git a/src/twn_camera.c b/src/twn_camera.c index 6bebd52..d32e7db 100644 --- a/src/twn_camera.c +++ b/src/twn_camera.c @@ -6,7 +6,7 @@ #define CAMERA_NEAR_Z 0.1f -#define CAMERA_FAR_Z 1000.0f +// #define CAMERA_FAR_Z 400.0f Matrix4 camera_look_at(const Camera *const camera) { @@ -42,13 +42,13 @@ Matrix4 camera_perspective(const Camera *const camera) { const float aspect = ((float)ctx.base_render_width / (float)ctx.base_render_height); const float f = 1.0f / tanf(camera->fov * 0.5f); - const float fn = 1.0f / (CAMERA_NEAR_Z - CAMERA_FAR_Z); + const float fn = 1.0f / (CAMERA_NEAR_Z - camera->far_z); result.row[0].x = f / aspect; result.row[1].y = f; - result.row[2].z = (CAMERA_NEAR_Z + CAMERA_FAR_Z) * fn; + result.row[2].z = (CAMERA_NEAR_Z + camera->far_z) * fn; result.row[2].w = -1.0f; - result.row[3].z = 2.0f * CAMERA_NEAR_Z * CAMERA_FAR_Z * fn; + result.row[3].z = 2.0f * CAMERA_NEAR_Z * camera->far_z * fn; return result; } @@ -61,14 +61,14 @@ Matrix4 camera_orthographic(const Camera *const camera) { const float rl = 1.0f / (camera->viewbox[0].y - camera->viewbox[0].x); const float tb = 1.0f / (camera->viewbox[1].x - camera->viewbox[1].y); - const float fn = -1.0f / (CAMERA_FAR_Z - -CAMERA_FAR_Z); + const float fn = -1.0f / (camera->far_z - -camera->far_z); result.row[0].x = 2.0f * rl; result.row[1].y = 2.0f * tb; result.row[2].z = 2.0f * fn; result.row[3].x = -(camera->viewbox[0].y + camera->viewbox[0].x) * rl; result.row[3].y = -(camera->viewbox[1].x + camera->viewbox[1].y) * tb; - result.row[3].z = (CAMERA_FAR_Z + -CAMERA_FAR_Z) * fn; + result.row[3].z = (camera->far_z + -camera->far_z) * fn; result.row[3].w = 1.0f; return result; diff --git a/src/twn_camera_c.h b/src/twn_camera_c.h index 602af79..df3078b 100644 --- a/src/twn_camera_c.h +++ b/src/twn_camera_c.h @@ -12,8 +12,9 @@ typedef struct Camera { Vec3 pos; /* eye position */ Vec3 target; /* normalized target vector */ Vec3 up; /* normalized up vector */ - float fov; /* field of view, in radians */ Vec2 viewbox[2]; /* othrographic aabb, ((left, right), (top, bottom)) */ + float fov; /* field of view, in radians */ + float far_z; } Camera; Matrix4 camera_look_at(const Camera *camera); diff --git a/src/twn_loop.c b/src/twn_loop.c index 6b145a7..4f3bf7a 100644 --- a/src/twn_loop.c +++ b/src/twn_loop.c @@ -631,7 +631,7 @@ static bool initialize(void) { input_state_init(&ctx.input); - ctx.render_double_buffered = true; + ctx.render_double_buffered = false; ctx.window_mouse_resident = true; ctx.game.fog_color = (Color){ 255, 255, 255, 255 }; /* TODO: pick some grey? */