#ifndef RENDER_RENDERER_H #define RENDER_RENDERER_H /* * Painterly renderer ("Waking Life" look). * * The scene is drawn into an offscreen target (color + view normal/depth), * then an ink pass draws boiling outlines, misregistered fills and paper grain * onto the screen. Geometry wobbles in the vertex shaders; the animation * steps at BOIL_FPS like hand-drawn frames. * * Per frame: * Renderer_beginFrame * Renderer_beginShadowPass, Renderer_drawShadowCaster..., Renderer_endShadowPass * Renderer_beginScenePass, Renderer_drawMesh... * (sky) * Renderer_endFrame -> ink pass to the screen */ #include #include "core/gl.h" #include "math/frustum.h" #include "math/linalg.h" #include "render/camera.h" #include "render/figure.h" #include "render/mesh.h" typedef struct { Vec3 sun_direction; /* towards the sun, may be below the horizon */ Vec3 light_direction; /* towards the key light (sun by day, moon by night) */ Vec3 light_color; /* tint of lit areas */ Vec3 shadow_color; /* tint of shaded areas */ Vec3 sky_top; Vec3 sky_horizon; float shadow_strength; /* 0..1, fades out around sunrise and sunset */ float day_factor; /* 0 = night, 1 = day */ Vec3 fire_position; /* a campfire's light ... */ float fire_strength; /* ... and how bright it is (0 = none) */ float wet; /* 0..1 everything wet from rain (darker, the ground damp) */ float overcast; /* 0..1 clouded over (the sky: more and darker clouds, no sun, moon or stars) */ } Lighting; typedef struct { GLuint program; GLint model, view, projection, light_space, boil_time; GLint view_pos, light_dir, light_color, shadow_color, sky_top, sky_horizon; GLint shadow_strength, shadow_map, fire_light; GLint terrain_size, grass_depth, wear_map, water_map, surface_map; /* terrain only */ GLint decal_size; /* things lying on the ground: sink with it */ GLint tint; /* color multiplier and ember glow */ GLint puff; /* > 0: soft and see-through (smoke), this thick */ GLint grass; /* grass blades: terrain size while drawing them */ GLint rain_wet; /* everything wet from rain (0..1) */ GLint holes, hole_size, hole_count; /* holes in the ground (basements): not drawn there */ } SceneShader; typedef struct { GLuint program; GLint model, light_space, boil_time; } ShadowShader; typedef struct { GLuint program; GLint color_tex, normal_depth_tex, texel, boil_time, time, drunk, dark; } InkShader; typedef struct { GLuint program; GLint view_proj, view, light_space, shadow_pass, boil_time; GLint figure_pos, facing, card_center, card_u, card_v, card_min, card_max, joints; GLint skin, hair, shirt, pants, shoes, hair_style, long_sleeves, cast; GLint head_forward, head_up, chest_forward, waist_bend, face, expression; GLint stream, stream_kind, stream_width; GLint garment, undress, top, jacket_tied, belly, wet, hood, hat, hat_color; GLint cig_a, cig_tip, cig_glow, jacket, uri_a, uri_b, uri; GLint species, tail_a, tail_b; GLint view_pos, light_dir, light_color, shadow_color, sky_top, sky_horizon; GLint shadow_strength, shadow_map, fire_light; } FigureShader; /* Offscreen target the scene is painted into. */ typedef struct { GLuint fbo; GLuint color; /* RGBA8 */ GLuint normal_depth; /* RGBA16F: view-space normal, view distance */ GLuint depth; int width; int height; } SceneTarget; typedef struct { int width; int height; float time; /* continuous clock (sky) */ float boil_time; /* animation clock, stepped at BOIL_FPS */ float drunk; /* 0..1: double vision and wavering in the ink pass */ float dark; /* 0..1: fade to black (sleeping) */ SceneShader scene; ShadowShader shadow; InkShader ink; FigureShader figure; GLuint pass_program; /* program of the current pass (shadow or scene) */ Vec3 viewer_pos; /* camera position during the scene pass */ Vec3 light_dir; /* key light direction during the shadow pass */ Vec3 shadow_focus; /* middle of the shadowed area */ bool shadow_pass; SceneTarget target; GLuint fullscreen_vao; GLuint shadow_fbo; GLuint shadow_map; int shadow_size; Mat4 light_space; Frustum frustum; /* of the current pass: what lies outside isn't drawn */ struct { int drawn, culled; } stats; /* this frame */ } Renderer; bool Renderer_init(Renderer *r); void Renderer_shutdown(Renderer *r); /* Binds and clears the offscreen target. time = real seconds since start. */ void Renderer_beginFrame(Renderer *r, int width, int height, float time); /* Could something this big (a sphere) show in the current pass? Every draw call checks this itself; use it to skip work before drawing. */ bool Renderer_inView(Renderer *r, Vec3 center, float radius); /* Shadows cover an area around focus (usually just ahead of the camera). */ void Renderer_beginShadowPass(Renderer *r, const Lighting *light, Vec3 focus); void Renderer_drawShadowCaster(Renderer *r, const Mesh *mesh, Mat4 model); void Renderer_endShadowPass(Renderer *r); /* Draws a 2D painted person in the current pass (shadow or scene). */ void Renderer_drawFigure(Renderer *r, const FigurePose *pose); void Renderer_beginScenePass(Renderer *r, const Camera *camera, const Lighting *light); /* Back to the scene pass after the sky (its settings still hold): what floats in the air. */ void Renderer_beginAirPass(Renderer *r); /* Like Renderer_drawMesh, darkened by rgb and glowing like embers by glow (0..1). */ void Renderer_drawMeshTinted(Renderer *r, const Mesh *mesh, Mat4 model, Vec3 rgb, float glow); /* Like Renderer_drawMeshTinted, but no ink outline round it and nothing hides behind it (smoke). */ /* Smoke: a soft, see-through ball (edges fading out), this thick (0..1). */ void Renderer_drawPuff(Renderer *r, const Mesh *mesh, Mat4 model, Vec3 rgb, float alpha); void Renderer_drawSmoke(Renderer *r, const Mesh *mesh, Mat4 model, Vec3 rgb); /* Grass blades (see world/meadow.h): trampled with the terrain, swaying. */ void Renderer_drawGrass(Renderer *r, const Mesh *mesh, float terrain_size, float grass_depth); void Renderer_drawMesh(Renderer *r, const Mesh *mesh, Mat4 model); /* Something lying flat on the ground (roads, sick): sinks with trampled grass like the ground itself, and gets wet with it. Draw after the terrain. */ void Renderer_drawDecal(Renderer *r, const Mesh *mesh, Mat4 model, float terrain_size); /* * Ground heightfield (world-space mesh). wear_map is an R8 texture covering * the terrain square: 0 = fresh meadow, 1 = trampled bare path. water_map is * RGBA8 over the same square: soil moisture, standing water, pee, mud * (see world/wetness.h); surface_map too: asphalt, concrete, gravel, bare * earth (see Site_surface). */ /* Holes in the ground drawn next (up to RENDER_HOLES): each a rectangle, middle x, z, its x axis (cos, sin) and half sizes x, z. */ #define RENDER_HOLES 8 void Renderer_setHoles(Renderer *r, const float (*rects)[6], int count); void Renderer_drawTerrain(Renderer *r, const Mesh *mesh, GLuint wear_map, GLuint water_map, GLuint surface_map, float size, float grass_depth); /* Ink pass: composes the offscreen target onto the screen. */ void Renderer_endFrame(Renderer *r); #endif /* RENDER_RENDERER_H */