gfx: render pass sorting

main
Dominik Madarász 2024-08-23 21:28:40 +02:00
parent 7f90d2304c
commit 87e5d825e6
11 changed files with 783 additions and 45 deletions

View File

@ -242,6 +242,7 @@ typedef float mat44[16];
void frustum44(mat44 m, float l, float r, float b, float t, float n, float f); void frustum44(mat44 m, float l, float r, float b, float t, float n, float f);
void perspective44(mat44 m, float fovy_degrees, float aspect, float nearp, float farp); void perspective44(mat44 m, float fovy_degrees, float aspect, float nearp, float farp);
void lookat44(mat44 m, vec3 eye, vec3 center, vec3 up); void lookat44(mat44 m, vec3 eye, vec3 center, vec3 up);
vec3 pos44(mat44 m);
void translation44(mat44 m, float x, float y, float z); void translation44(mat44 m, float x, float y, float z);
void translate44(mat44 m, float x, float y, float z); void translate44(mat44 m, float x, float y, float z);
void relocate44(mat44 m, float x, float y, float z); void relocate44(mat44 m, float x, float y, float z);
@ -1328,8 +1329,12 @@ enum SHADING_MODE {
}; };
enum RENDER_PASS { enum RENDER_PASS {
RENDER_PASS_OPAQUE, RENDER_PASS_OPAQUE,
RENDER_PASS_TRANSPARENT,
RENDER_PASS_OVERRIDES_BEGIN,
RENDER_PASS_SHADOW, RENDER_PASS_SHADOW,
RENDER_PASS_LIGHTMAP, RENDER_PASS_LIGHTMAP,
RENDER_PASS_CUSTOM,
RENDER_PASS_OVERRIDES_END,
NUM_RENDER_PASSES NUM_RENDER_PASSES
}; };
enum MODEL_UNIFORMS { enum MODEL_UNIFORMS {
@ -1380,6 +1385,7 @@ typedef struct model_t {
void *verts; void *verts;
int num_verts; int num_verts;
void *tris; void *tris;
vec3 *meshcenters;
int num_tris; int num_tris;
handle vao, ibo, vbo, vao_instanced; handle vao, ibo, vbo, vao_instanced;
int* lod_collapse_map; int* lod_collapse_map;
@ -1413,6 +1419,8 @@ enum BILLBOARD_MODE {
void model_render(model_t, mat44 proj, mat44 view, mat44 model, int shader); void model_render(model_t, mat44 proj, mat44 view, mat44 model, int shader);
void model_render_skeleton(model_t, mat44 model); void model_render_skeleton(model_t, mat44 model);
void model_render_instanced(model_t, mat44 proj, mat44 view, mat44 *models, int shader, unsigned count); void model_render_instanced(model_t, mat44 proj, mat44 view, mat44 *models, int shader, unsigned count);
void model_render_instanced_pass(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count, int pass);
void model_render_pass(model_t m, mat44 proj, mat44 view, mat44 model, int shader, int pass);
void model_set_texture(model_t, texture_t t); void model_set_texture(model_t, texture_t t);
bool model_get_bone_pose(model_t m, unsigned joint, mat34 *out); bool model_get_bone_pose(model_t m, unsigned joint, mat34 *out);
void model_destroy(model_t); void model_destroy(model_t);

64
demos/06-sorting.c 100644
View File

@ -0,0 +1,64 @@
// render map
#include "v4k.h"
int main() {
window_create(80, WINDOW_MSAA8);
window_title(__FILE__);
window_fps_unlock();
// load all fx files
fx_load("fx**.fs");
// load skybox
// skybox_t sky = skybox(flag("--mie") ? 0 : "hdr/Tokyo_BigSight_1k.hdr", 0); // --mie for rayleigh/mie scattering
skybox_t sky = skybox("bridge3", 0); // --mie for rayleigh/mie scattering
// load static scene
model_t map;
map = model(option("--model","sorting_test.obj"), 0); // MODEL_NO_TEXTURES);
shader_bind(map.program);
skybox_sh_shader(&sky);
// translation44(map.pivot, 0,-1,0);
// rotate44(map.pivot, -90,1,0,0);
// scale44(map.pivot, 10,10,10);
// camera
camera_t cam = camera();
cam.speed *= 0.05f;
// demo loop
while (window_swap())
{
// input
if( input_down(KEY_ESC) ) break;
if( input_down(KEY_F5) ) window_reload();
if( input_down(KEY_F11) ) window_fullscreen( window_has_fullscreen() ^ 1 );
if( input_down(KEY_X) ) window_screenshot(__FILE__ ".png");
if( input_down(KEY_Z) ) window_record(__FILE__ ".mp4");
// fps camera
bool active = ui_active() || ui_hover() || gizmo_active() ? false : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R);
if( active ) cam.speed = clampf(cam.speed + input_diff(MOUSE_W) / 10, 0.05f, 5.0f);
vec2 mouse = scale2(vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active);
vec3 wasdecq = scale3(vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-(input(KEY_C)||input(KEY_Q)),input(KEY_W)-input(KEY_S)), cam.speed);
camera_moveby(&cam, wasdecq);
camera_fps(&cam, mouse.x,mouse.y);
window_cursor( !active );
// draw skybox
profile("Skybox") {
skybox_render(&sky, cam.proj, cam.view);
}
mat44 M; copy44(M, map.pivot);// translate44(M, 0,0,0); scale44(M, scale,scale,scale);
// apply post-fxs from here
fx_begin();
model_render_pass(map, cam.proj, cam.view, M, 0, -1);
// post-fxs end here
fx_end(0);
}
}

View File

@ -0,0 +1,52 @@
# Blender 4.2.1 LTS MTL File: 'None'
# www.blender.org
newmtl Material
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2
map_Kd E:/v4games/v4k/demos/art/matcaps/test_steel.jpg
newmtl Material.001
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 1.000000
illum 2
map_Kd E:/v4games/v4k/demos/art/matcaps/material3.jpg
newmtl Material.002
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Kd 0.059941 0.801453 0.027650
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 0.228070
illum 9
newmtl Material.003
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Kd 0.800063 0.776954 0.209224
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 0.480702
illum 9
newmtl Material.004
Ns 250.000000
Ka 1.000000 1.000000 1.000000
Kd 0.015818 0.013069 0.801024
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.500000
d 0.294737
illum 9

View File

@ -0,0 +1,173 @@
# Blender 4.2.1 LTS
# www.blender.org
mtllib sorting_test.mtl
o Cube.001
v -8.122441 2.199780 2.665483
v -8.122441 2.199780 -2.665483
v 8.122441 2.199780 2.665483
v 8.122441 2.199780 -2.665483
v -8.122441 7.530746 2.665483
v -8.122441 7.530746 -2.665483
v 8.122441 7.530746 2.665483
v 8.122441 7.530746 -2.665483
v 15.783228 15.783226 -13.899874
v 17.600002 17.600000 2.199389
v -15.783228 15.783226 -13.899874
v -17.600002 17.600000 2.199389
v 15.783228 -15.783228 -13.899874
v 17.600002 -17.600002 2.199389
v -15.783228 -15.783228 -13.899874
v -17.600002 -17.600002 2.199389
v -17.600002 17.600000 -13.800612
v -17.600002 -17.600002 -13.800612
v 17.600002 17.600000 -13.800612
v 17.600002 -17.600002 -13.800612
v -15.783228 15.783226 0.175428
v -15.783228 -15.783228 0.175428
v 15.783228 15.783226 0.175428
v 15.783228 -15.783228 0.175428
v -6.691334 2.669416 -2.804010
v -6.691334 2.669416 -7.195704
v 6.691334 2.669416 -2.804010
v 6.691334 2.669416 -7.195704
v -6.691334 7.061110 -2.804010
v -6.691334 7.061110 -7.195704
v 6.691334 7.061110 -2.804010
v 6.691334 7.061110 -7.195704
v -8.122442 -7.045201 2.665483
v -8.122442 -7.045201 -2.665483
v 8.122442 -7.045201 2.665483
v 8.122442 -7.045201 -2.665483
v -8.122442 -1.714234 2.665483
v -8.122442 -1.714234 -2.665483
v 8.122442 -1.714234 2.665483
v 8.122442 -1.714234 -2.665483
v -6.691334 -6.575565 -2.804010
v -6.691334 -6.575565 -7.195704
v 6.691334 -6.575565 -2.804010
v 6.691334 -6.575565 -7.195704
v -6.691334 -2.183871 -2.804010
v -6.691334 -2.183871 -7.195704
v 6.691334 -2.183871 -2.804010
v 6.691334 -2.183871 -7.195704
v -8.122442 -15.615585 2.665483
v -8.122442 -15.615585 -2.665483
v 8.122442 -15.615585 2.665483
v 8.122442 -15.615585 -2.665483
v -8.122442 -10.284618 2.665483
v -8.122442 -10.284618 -2.665483
v 8.122442 -10.284618 2.665483
v 8.122442 -10.284618 -2.665483
v -6.691334 -15.145948 -2.804010
v -6.691334 -15.145948 -7.195704
v 6.691334 -15.145948 -2.804010
v 6.691334 -15.145948 -7.195704
v -6.691334 -10.754253 -2.804010
v -6.691334 -10.754253 -7.195704
v 6.691334 -10.754253 -2.804010
v 6.691334 -10.754253 -7.195704
vn -0.0000 -1.0000 -0.0000
vn 1.0000 -0.0000 -0.0000
vn -0.0000 1.0000 -0.0000
vn -1.0000 -0.0000 -0.0000
vn -0.0000 -0.0000 1.0000
vn -0.0000 -0.0000 -1.0000
vn -0.0000 0.7442 -0.6680
vn -0.0546 -0.0000 -0.9985
vn 0.7071 0.7071 -0.0000
vn -0.0000 -0.0546 -0.9985
vn 0.0546 -0.0000 -0.9985
vn -0.7071 0.7071 -0.0000
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.625000 0.500000
vt 0.375000 0.500000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.125000 0.500000
vt 0.125000 0.750000
vt 0.875000 0.500000
vt 0.875000 0.750000
vt 0.815610 0.670937
vt 1.086685 0.728059
vt 1.066389 0.553695
vt 0.851135 0.506484
vt 0.286824 0.345736
vt 0.332150 0.541159
vt 0.086713 0.717651
vt 0.066236 0.538218
vt 1.066236 0.538218
vt 1.086713 0.717651
vt 0.816752 0.660765
vt 0.852741 0.491363
vt 0.621682 0.280820
vt 0.289035 0.361544
vt 0.620623 0.297043
vt 0.589978 0.486593
vt 0.333337 0.554977
vt 0.086685 0.728059
vt 0.589978 0.500567
vt 0.066389 0.553695
s 0
usemtl Material.001
f 1/1/1 2/2/1 4/3/1 3/4/1
f 3/4/2 4/3/2 8/5/2 7/6/2
f 7/6/3 8/5/3 6/7/3 5/8/3
f 5/8/4 6/7/4 2/9/4 1/10/4
f 3/11/5 7/6/5 5/8/5 1/12/5
f 8/5/6 4/13/6 2/14/6 6/7/6
f 33/1/1 34/2/1 36/3/1 35/4/1
f 35/4/2 36/3/2 40/5/2 39/6/2
f 39/6/3 40/5/3 38/7/3 37/8/3
f 37/8/4 38/7/4 34/9/4 33/10/4
f 35/11/5 39/6/5 37/8/5 33/12/5
f 40/5/6 36/13/6 34/14/6 38/7/6
f 49/1/1 50/2/1 52/3/1 51/4/1
f 51/4/2 52/3/2 56/5/2 55/6/2
f 55/6/3 56/5/3 54/7/3 53/8/3
f 53/8/4 54/7/4 50/9/4 49/10/4
f 51/11/5 55/6/5 53/8/5 49/12/5
f 56/5/6 52/13/6 50/14/6 54/7/6
usemtl Material
f 13/15/3 15/16/3 22/17/3 24/18/3
f 12/19/4 17/20/4 18/21/4 16/22/4
f 16/23/1 18/24/1 20/25/1 14/26/1
f 14/26/5 10/27/5 12/19/5 16/23/5
f 21/28/7 12/19/7 23/29/7
f 14/26/2 20/25/2 19/30/2 10/27/2
f 11/31/8 15/32/8 18/21/8 17/20/8
f 12/19/9 11/31/9 17/20/9
f 15/16/10 13/15/10 20/25/10 18/24/10
f 13/15/11 9/33/11 19/30/11 20/25/11
f 23/29/6 24/18/6 22/17/6 21/28/6
f 15/32/2 11/31/2 21/28/2 22/34/2
f 9/33/4 13/15/4 24/18/4 23/29/4
f 21/28/9 11/31/9 12/19/9
f 10/27/7 23/29/7 12/19/7
f 23/29/12 10/27/12 9/33/12
f 10/27/12 19/30/12 9/33/12
usemtl Material.002
f 25/1/1 26/2/1 28/3/1 27/4/1
f 27/4/2 28/3/2 32/5/2 31/6/2
f 31/6/3 32/5/3 30/7/3 29/8/3
f 29/8/4 30/7/4 26/9/4 25/10/4
f 27/11/5 31/6/5 29/8/5 25/12/5
f 32/5/6 28/13/6 26/14/6 30/7/6
usemtl Material.004
f 41/1/1 42/2/1 44/3/1 43/4/1
f 43/4/2 44/3/2 48/5/2 47/6/2
f 47/6/3 48/5/3 46/7/3 45/8/3
f 45/8/4 46/7/4 42/9/4 41/10/4
f 43/11/5 47/6/5 45/8/5 41/12/5
f 48/5/6 44/13/6 42/14/6 46/7/6
usemtl Material.003
f 57/1/1 58/2/1 60/3/1 59/4/1
f 59/4/2 60/3/2 64/5/2 63/6/2
f 63/6/3 64/5/3 62/7/3 61/8/3
f 61/8/4 62/7/4 58/9/4 57/10/4
f 59/11/5 63/6/5 61/8/5 57/12/5
f 64/5/6 60/13/6 58/14/6 62/7/6

View File

@ -15135,6 +15135,7 @@ API void ortho44(mat44 m, float l, float r, float b, float t, float n, float f);
API void frustum44(mat44 m, float l, float r, float b, float t, float n, float f); API void frustum44(mat44 m, float l, float r, float b, float t, float n, float f);
API void perspective44(mat44 m, float fovy_degrees, float aspect, float nearp, float farp); API void perspective44(mat44 m, float fovy_degrees, float aspect, float nearp, float farp);
API void lookat44(mat44 m, vec3 eye, vec3 center, vec3 up); API void lookat44(mat44 m, vec3 eye, vec3 center, vec3 up);
API vec3 pos44(mat44 m);
// --- // ---
API void translation44(mat44 m, float x, float y, float z); API void translation44(mat44 m, float x, float y, float z);
API void translate44(mat44 m, float x, float y, float z); API void translate44(mat44 m, float x, float y, float z);
@ -17575,8 +17576,13 @@ enum SHADING_MODE {
enum RENDER_PASS { enum RENDER_PASS {
RENDER_PASS_OPAQUE, RENDER_PASS_OPAQUE,
RENDER_PASS_TRANSPARENT,
RENDER_PASS_OVERRIDES_BEGIN,
RENDER_PASS_SHADOW, RENDER_PASS_SHADOW,
RENDER_PASS_LIGHTMAP, RENDER_PASS_LIGHTMAP,
RENDER_PASS_CUSTOM, // make sure to apply renderstate before calling this
RENDER_PASS_OVERRIDES_END,
NUM_RENDER_PASSES NUM_RENDER_PASSES
}; };
@ -17637,6 +17643,7 @@ typedef struct model_t {
void *verts; void *verts;
int num_verts; int num_verts;
void *tris; void *tris;
vec3 *meshcenters;
int num_tris; int num_tris;
handle vao, ibo, vbo, vao_instanced; handle vao, ibo, vbo, vao_instanced;
@ -17677,6 +17684,8 @@ API void model_skybox(model_t*, skybox_t sky, bool load_sh);
API void model_render(model_t, mat44 proj, mat44 view, mat44 model, int shader); API void model_render(model_t, mat44 proj, mat44 view, mat44 model, int shader);
API void model_render_skeleton(model_t, mat44 model); API void model_render_skeleton(model_t, mat44 model);
API void model_render_instanced(model_t, mat44 proj, mat44 view, mat44 *models, int shader, unsigned count); API void model_render_instanced(model_t, mat44 proj, mat44 view, mat44 *models, int shader, unsigned count);
API void model_render_instanced_pass(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count, int pass);
API void model_render_pass(model_t m, mat44 proj, mat44 view, mat44 model, int shader, int pass);
API void model_set_texture(model_t, texture_t t); API void model_set_texture(model_t, texture_t t);
API bool model_get_bone_pose(model_t m, unsigned joint, mat34 *out); API bool model_get_bone_pose(model_t m, unsigned joint, mat34 *out);
API void model_destroy(model_t); API void model_destroy(model_t);
@ -377451,6 +377460,20 @@ void lookat44(mat44 m, vec3 eye, vec3 center, vec3 up) {
m[ 8] = r.z; m[ 9] = u.z; m[10] = -f.z; m[11] = 0; m[ 8] = r.z; m[ 9] = u.z; m[10] = -f.z; m[11] = 0;
m[12] = -dot3(r, eye); m[13] = -dot3(u, eye); m[14] = dot3(f, eye); m[15] = 1; m[12] = -dot3(r, eye); m[13] = -dot3(u, eye); m[14] = dot3(f, eye); m[15] = 1;
} }
vec3 pos44(mat44 m) {
vec3 position;
// The camera position is the negation of the translation vector
// transformed by the inverse of the rotation matrix.
// Since the upper-left 3x3 part of the view matrix is orthogonal,
// its inverse is equal to its transpose.
position.x = -(m[0] * m[12] + m[1] * m[13] + m[2] * m[14]);
position.y = -(m[4] * m[12] + m[5] * m[13] + m[6] * m[14]);
position.z = -(m[8] * m[12] + m[9] * m[13] + m[10] * m[14]);
return position;
}
// --- // ---
void translation44(mat44 m, float x, float y, float z) { // identity4 + translate4 void translation44(mat44 m, float x, float y, float z) { // identity4 + translate4
m[ 0] = 1.0f; m[ 1] = 0.0f; m[ 2] = 0.0f; m[ 3] = 0.0f; m[ 0] = 1.0f; m[ 1] = 0.0f; m[ 2] = 0.0f; m[ 3] = 0.0f;
@ -382590,6 +382613,16 @@ max_aniso = 4;
t->n = n; t->n = n;
t->flags = flags; t->flags = flags;
t->filename = t->filename ? t->filename : ""; t->filename = t->filename ? t->filename : "";
t->transparent = 0;
if (t->n == 4 && pixels) {
for (int i = 0; i < w * h; i++) {
if (((uint8_t *)pixels)[i * 4 + 3] < 255) {
t->transparent = 1;
break;
}
}
}
return t->id; return t->id;
} }
@ -382598,7 +382631,6 @@ texture_t texture_create(unsigned w, unsigned h, unsigned n, const void *pixels,
texture_t texture = {0}; texture_t texture = {0};
glGenTextures( 1, &texture.id ); glGenTextures( 1, &texture.id );
texture_update( &texture, w, h, n, pixels, flags ); texture_update( &texture, w, h, n, pixels, flags );
texture.transparent = texture.n > 3; // @fixme: should be true only if any pixel.a == 0
return texture; return texture;
} }
@ -384902,12 +384934,12 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view,
glUniformMatrix4fv( loc, 1, GL_FALSE, vp); glUniformMatrix4fv( loc, 1, GL_FALSE, vp);
} }
if( (loc = glGetUniformLocation(shader, "u_cam_pos")) >= 0 ) { if( (loc = glGetUniformLocation(shader, "u_cam_pos")) >= 0 ) {
vec3 pos = vec3(view[12], view[13], view[14]); vec3 pos = pos44(view);
glUniform3fv( loc, 1, &pos.x ); glUniform3fv( loc, 1, &pos.x );
} }
else else
if( (loc = glGetUniformLocation(shader, "cam_pos")) >= 0 ) { if( (loc = glGetUniformLocation(shader, "cam_pos")) >= 0 ) {
vec3 pos = vec3(view[12], view[13], view[14]); vec3 pos = pos44(view);
glUniform3fv( loc, 1, &pos.x ); glUniform3fv( loc, 1, &pos.x );
} }
if( (loc = glGetUniformLocation(shader, "u_cam_dir")) >= 0 ) { if( (loc = glGetUniformLocation(shader, "u_cam_dir")) >= 0 ) {
@ -385208,9 +385240,13 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) {
q->textures = CALLOC(hdr->num_meshes * 8, sizeof(GLuint)); q->textures = CALLOC(hdr->num_meshes * 8, sizeof(GLuint));
q->colormaps = CALLOC(hdr->num_meshes * 8, sizeof(vec4)); q->colormaps = CALLOC(hdr->num_meshes * 8, sizeof(vec4));
m->meshcenters = CALLOC(hdr->num_meshes, sizeof(vec3));
for(int i = 0; i < (int)hdr->num_meshes; i++) { for(int i = 0; i < (int)hdr->num_meshes; i++) {
int invalid = texture_checker().id; int invalid = texture_checker().id;
q->textures[i] = invalid; q->textures[i] = invalid;
GLfloat *pos = verts[q->meshes[i].first_vertex].position;
m->meshcenters[i] = vec3(pos[0], pos[1], pos[2]);
} }
const char *str = hdr->ofs_text ? (char *)&q->buf[hdr->ofs_text] : ""; const char *str = hdr->ofs_text ? (char *)&q->buf[hdr->ofs_text] : "";
@ -385304,7 +385340,7 @@ void model_load_pbr_layer(material_layer_t *layer, const char *texname, bool loa
static static
void model_load_pbr(material_t *mt) { void model_load_pbr(material_t *mt) {
// initialise default colors // initialise default colors
mt->layer[MATERIAL_CHANNEL_DIFFUSE].map.color = vec4(0.5,0.5,0.5,0.5); mt->layer[MATERIAL_CHANNEL_DIFFUSE].map.color = vec4(0.5,0.5,0.5,1.0);
mt->layer[MATERIAL_CHANNEL_NORMALS].map.color = vec4(0,0,0,0); mt->layer[MATERIAL_CHANNEL_NORMALS].map.color = vec4(0,0,0,0);
mt->layer[MATERIAL_CHANNEL_SPECULAR].map.color = vec4(0,0,0,0); mt->layer[MATERIAL_CHANNEL_SPECULAR].map.color = vec4(0,0,0,0);
mt->layer[MATERIAL_CHANNEL_SPECULAR].value = 1.0f; // specular_shininess mt->layer[MATERIAL_CHANNEL_SPECULAR].value = 1.0f; // specular_shininess
@ -385504,13 +385540,21 @@ void model_set_renderstates(model_t *m) {
// Opaque pass // Opaque pass
renderstate_t *opaque_rs = &m->rs[RENDER_PASS_OPAQUE]; renderstate_t *opaque_rs = &m->rs[RENDER_PASS_OPAQUE];
{ {
opaque_rs->blend_enabled = 1; opaque_rs->blend_enabled = 0;
opaque_rs->blend_src = GL_SRC_ALPHA;
opaque_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA;
opaque_rs->cull_face_mode = GL_BACK; opaque_rs->cull_face_mode = GL_BACK;
opaque_rs->front_face = GL_CW; opaque_rs->front_face = GL_CW;
} }
// Transparent pass
renderstate_t *transparent_rs = &m->rs[RENDER_PASS_TRANSPARENT];
{
transparent_rs->blend_enabled = 1;
transparent_rs->blend_src = GL_SRC_ALPHA;
transparent_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA;
transparent_rs->cull_face_mode = GL_BACK;
transparent_rs->front_face = GL_CW;
}
// Shadow pass @todo // Shadow pass @todo
renderstate_t *shadow_rs = &m->rs[RENDER_PASS_SHADOW]; renderstate_t *shadow_rs = &m->rs[RENDER_PASS_SHADOW];
{ {
@ -385805,23 +385849,115 @@ void shader_colormap_model_internal(const char *col_name, const char *bool_name,
if( c.texture ) shader_texture( tex_name, *c.texture ); if( c.texture ) shader_texture( tex_name, *c.texture );
} }
typedef struct drawcall_t {
model_t *m;
int mesh;
union {
uint64_t order;
struct {
uint32_t tex;
float distance;
};
};
} drawcall_t;
static static
void model_draw_call(model_t m, int shader) { int drawcall_compare(const void *a, const void *b) {
const drawcall_t *da = a, *db = b;
return da->order < db->order ? 1 : da->order > db->order ? -1 : 0;
}
static
void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_mat) {
if(!m.iqm) return; if(!m.iqm) return;
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
handle old_shader = last_shader; handle old_shader = last_shader;
shader_bind(shader); shader_bind(shader);
renderstate_t *rs = &m.rs[RENDER_PASS_OPAQUE]; int rs_idx = model_getpass();
renderstate_t *rs = &m.rs[rs_idx];
renderstate_apply(rs);
glBindVertexArray( q->vao ); glBindVertexArray( q->vao );
struct iqmtriangle *tris = NULL; static array(int) required_rs = 0;
array_resize(required_rs, q->nummeshes);
for(int i = 0; i < q->nummeshes; i++) { for(int i = 0; i < q->nummeshes; i++) {
struct iqmmesh *im = &q->meshes[i]; struct iqmmesh *im = &q->meshes[i];
required_rs[i] = rs_idx;
if (required_rs[i] < RENDER_PASS_OVERRIDES_BEGIN) {
if (m.materials[i].layer[0].map.color.a < 1 || (m.materials[i].layer[0].map.texture && m.materials[i].layer[0].map.texture->transparent)) {
required_rs[i] = RENDER_PASS_TRANSPARENT;
}
if (m.shading == SHADING_PBR && (m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.color.a < 1 || (m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.texture && m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.texture->transparent))){
required_rs[i] = RENDER_PASS_TRANSPARENT;
}
}
}
static array(drawcall_t) drawcalls = 0;
array_resize(drawcalls, 0);
if (rs_idx > RENDER_PASS_OVERRIDES_BEGIN) {
for(int i = 0; i < q->nummeshes; i++) {
array_push(drawcalls, (drawcall_t){i, 0});
}
} else {
if(pass == -1 || pass == RENDER_PASS_OPAQUE) {
for(int i = 0; i < q->nummeshes; i++) {
// collect opaque drawcalls
if (required_rs[i] == RENDER_PASS_OPAQUE) {
drawcall_t call;
call.mesh = i;
call.tex = m.textures[i];
call.distance = -1;
if (m.shading == SHADING_PBR)
call.tex = m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.texture ? m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.texture->id : m.materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture ? m.materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture->id : texture_checker().id;
array_push(drawcalls, call);
}
}
}
if(pass == -1 || pass == RENDER_PASS_TRANSPARENT) {
for(int i = 0; i < q->nummeshes; i++) {
// collect transparent drawcalls
if (required_rs[i] == RENDER_PASS_TRANSPARENT) {
drawcall_t call;
call.mesh = i;
call.tex = m.textures[i];
// calculate distance from camera
// @todo: improve me, uses first mesh triangle
{
call.distance = len3(sub3(cam_pos, transform344(model_mat, m.meshcenters[i])));
}
if (m.shading == SHADING_PBR)
call.tex = m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.texture ? m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.texture->id : m.materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture ? m.materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture->id : texture_checker().id;
array_push(drawcalls, call);
}
}
}
}
// sort drawcalls by order
array_sort(drawcalls, drawcall_compare);
struct iqmtriangle *tris = NULL;
for(int di = 0; di < array_count(drawcalls); di++) {
int i = drawcalls[di].mesh;
struct iqmmesh *im = &q->meshes[i];
if (pass != -1 && pass != required_rs[i]) continue;
if (rs_idx != required_rs[i]) {
rs_idx = required_rs[i];
rs = &m.rs[rs_idx];
renderstate_apply(rs);
}
if (m.shading != SHADING_PBR) { if (m.shading != SHADING_PBR) {
shader_texture_unit("u_texture2d", q->textures[i], texture_unit()); shader_texture_unit("u_texture2d", q->textures[i], texture_unit());
@ -385860,7 +385996,7 @@ void model_draw_call(model_t m, int shader) {
shader_bind(old_shader); shader_bind(old_shader);
} }
void model_render_instanced(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count) { void model_render_instanced_pass(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count, int pass) {
if(!m.iqm) return; if(!m.iqm) return;
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
@ -385873,11 +386009,19 @@ void model_render_instanced(model_t m, mat44 proj, mat44 view, mat44* models, in
} }
model_set_uniforms(m, shader > 0 ? shader : m.program, mv, proj, view, models[0]); model_set_uniforms(m, shader > 0 ? shader : m.program, mv, proj, view, models[0]);
model_draw_call(m, shader > 0 ? shader : m.program); model_draw_call(m, shader > 0 ? shader : m.program, pass, pos44(view), models[0]);
}
void model_render_instanced(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count) {
model_render_instanced_pass(m, proj, view, models, shader, count, -1);
}
void model_render_pass(model_t m, mat44 proj, mat44 view, mat44 model, int shader, int pass) {
model_render_instanced_pass(m, proj, view, (mat44*)model, shader, 1, pass);
} }
void model_render(model_t m, mat44 proj, mat44 view, mat44 model, int shader) { void model_render(model_t m, mat44 proj, mat44 view, mat44 model, int shader) {
model_render_instanced(m, proj, view, (mat44*)model, shader, 1); model_render_pass(m, proj, view, model, shader, -1);
} }
static inline static inline
@ -386216,6 +386360,7 @@ void model_destroy(model_t m) {
FREE(m.texture_names[i]); FREE(m.texture_names[i]);
} }
array_free(m.texture_names); array_free(m.texture_names);
FREE(m.meshcenters);
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
// if(m.mesh) mesh_destroy(m.mesh); // if(m.mesh) mesh_destroy(m.mesh);
@ -386239,6 +386384,7 @@ unsigned model_getpass() {
unsigned model_setpass(unsigned pass) { unsigned model_setpass(unsigned pass) {
ASSERT(pass < NUM_RENDER_PASSES); ASSERT(pass < NUM_RENDER_PASSES);
ASSERT(pass != RENDER_PASS_OVERRIDES_BEGIN && pass != RENDER_PASS_OVERRIDES_END);
unsigned old_pass = model_renderpass; unsigned old_pass = model_renderpass;
model_renderpass = pass; model_renderpass = pass;
return old_pass; return old_pass;
@ -386304,6 +386450,7 @@ void lightmap_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm
unsigned old_pass = model_setpass(RENDER_PASS_LIGHTMAP); unsigned old_pass = model_setpass(RENDER_PASS_LIGHTMAP);
for (int b = 0; b < bounces; b++) { for (int b = 0; b < bounces; b++) {
model_setpass(RENDER_PASS_LIGHTMAP);
for (int i = 0; i < array_count(lm->models); i++) { for (int i = 0; i < array_count(lm->models); i++) {
model_t *m = lm->models[i]; model_t *m = lm->models[i];
if (!m->lmdata) { if (!m->lmdata) {

View File

@ -522,6 +522,20 @@ void lookat44(mat44 m, vec3 eye, vec3 center, vec3 up) {
m[ 8] = r.z; m[ 9] = u.z; m[10] = -f.z; m[11] = 0; m[ 8] = r.z; m[ 9] = u.z; m[10] = -f.z; m[11] = 0;
m[12] = -dot3(r, eye); m[13] = -dot3(u, eye); m[14] = dot3(f, eye); m[15] = 1; m[12] = -dot3(r, eye); m[13] = -dot3(u, eye); m[14] = dot3(f, eye); m[15] = 1;
} }
vec3 pos44(mat44 m) {
vec3 position;
// The camera position is the negation of the translation vector
// transformed by the inverse of the rotation matrix.
// Since the upper-left 3x3 part of the view matrix is orthogonal,
// its inverse is equal to its transpose.
position.x = -(m[0] * m[12] + m[1] * m[13] + m[2] * m[14]);
position.y = -(m[4] * m[12] + m[5] * m[13] + m[6] * m[14]);
position.z = -(m[8] * m[12] + m[9] * m[13] + m[10] * m[14]);
return position;
}
// --- // ---
void translation44(mat44 m, float x, float y, float z) { // identity4 + translate4 void translation44(mat44 m, float x, float y, float z) { // identity4 + translate4
m[ 0] = 1.0f; m[ 1] = 0.0f; m[ 2] = 0.0f; m[ 3] = 0.0f; m[ 0] = 1.0f; m[ 1] = 0.0f; m[ 2] = 0.0f; m[ 3] = 0.0f;

View File

@ -243,6 +243,7 @@ API void ortho44(mat44 m, float l, float r, float b, float t, float n, float f);
API void frustum44(mat44 m, float l, float r, float b, float t, float n, float f); API void frustum44(mat44 m, float l, float r, float b, float t, float n, float f);
API void perspective44(mat44 m, float fovy_degrees, float aspect, float nearp, float farp); API void perspective44(mat44 m, float fovy_degrees, float aspect, float nearp, float farp);
API void lookat44(mat44 m, vec3 eye, vec3 center, vec3 up); API void lookat44(mat44 m, vec3 eye, vec3 center, vec3 up);
API vec3 pos44(mat44 m);
// --- // ---
API void translation44(mat44 m, float x, float y, float z); API void translation44(mat44 m, float x, float y, float z);
API void translate44(mat44 m, float x, float y, float z); API void translate44(mat44 m, float x, float y, float z);

View File

@ -974,6 +974,16 @@ max_aniso = 4;
t->n = n; t->n = n;
t->flags = flags; t->flags = flags;
t->filename = t->filename ? t->filename : ""; t->filename = t->filename ? t->filename : "";
t->transparent = 0;
if (t->n == 4 && pixels) {
for (int i = 0; i < w * h; i++) {
if (((uint8_t *)pixels)[i * 4 + 3] < 255) {
t->transparent = 1;
break;
}
}
}
return t->id; return t->id;
} }
@ -982,7 +992,6 @@ texture_t texture_create(unsigned w, unsigned h, unsigned n, const void *pixels,
texture_t texture = {0}; texture_t texture = {0};
glGenTextures( 1, &texture.id ); glGenTextures( 1, &texture.id );
texture_update( &texture, w, h, n, pixels, flags ); texture_update( &texture, w, h, n, pixels, flags );
texture.transparent = texture.n > 3; // @fixme: should be true only if any pixel.a == 0
return texture; return texture;
} }
@ -3286,12 +3295,12 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view,
glUniformMatrix4fv( loc, 1, GL_FALSE, vp); glUniformMatrix4fv( loc, 1, GL_FALSE, vp);
} }
if( (loc = glGetUniformLocation(shader, "u_cam_pos")) >= 0 ) { if( (loc = glGetUniformLocation(shader, "u_cam_pos")) >= 0 ) {
vec3 pos = vec3(view[12], view[13], view[14]); vec3 pos = pos44(view);
glUniform3fv( loc, 1, &pos.x ); glUniform3fv( loc, 1, &pos.x );
} }
else else
if( (loc = glGetUniformLocation(shader, "cam_pos")) >= 0 ) { if( (loc = glGetUniformLocation(shader, "cam_pos")) >= 0 ) {
vec3 pos = vec3(view[12], view[13], view[14]); vec3 pos = pos44(view);
glUniform3fv( loc, 1, &pos.x ); glUniform3fv( loc, 1, &pos.x );
} }
if( (loc = glGetUniformLocation(shader, "u_cam_dir")) >= 0 ) { if( (loc = glGetUniformLocation(shader, "u_cam_dir")) >= 0 ) {
@ -3592,9 +3601,13 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) {
q->textures = CALLOC(hdr->num_meshes * 8, sizeof(GLuint)); q->textures = CALLOC(hdr->num_meshes * 8, sizeof(GLuint));
q->colormaps = CALLOC(hdr->num_meshes * 8, sizeof(vec4)); q->colormaps = CALLOC(hdr->num_meshes * 8, sizeof(vec4));
m->meshcenters = CALLOC(hdr->num_meshes, sizeof(vec3));
for(int i = 0; i < (int)hdr->num_meshes; i++) { for(int i = 0; i < (int)hdr->num_meshes; i++) {
int invalid = texture_checker().id; int invalid = texture_checker().id;
q->textures[i] = invalid; q->textures[i] = invalid;
GLfloat *pos = verts[q->meshes[i].first_vertex].position;
m->meshcenters[i] = vec3(pos[0], pos[1], pos[2]);
} }
const char *str = hdr->ofs_text ? (char *)&q->buf[hdr->ofs_text] : ""; const char *str = hdr->ofs_text ? (char *)&q->buf[hdr->ofs_text] : "";
@ -3688,7 +3701,7 @@ void model_load_pbr_layer(material_layer_t *layer, const char *texname, bool loa
static static
void model_load_pbr(material_t *mt) { void model_load_pbr(material_t *mt) {
// initialise default colors // initialise default colors
mt->layer[MATERIAL_CHANNEL_DIFFUSE].map.color = vec4(0.5,0.5,0.5,0.5); mt->layer[MATERIAL_CHANNEL_DIFFUSE].map.color = vec4(0.5,0.5,0.5,1.0);
mt->layer[MATERIAL_CHANNEL_NORMALS].map.color = vec4(0,0,0,0); mt->layer[MATERIAL_CHANNEL_NORMALS].map.color = vec4(0,0,0,0);
mt->layer[MATERIAL_CHANNEL_SPECULAR].map.color = vec4(0,0,0,0); mt->layer[MATERIAL_CHANNEL_SPECULAR].map.color = vec4(0,0,0,0);
mt->layer[MATERIAL_CHANNEL_SPECULAR].value = 1.0f; // specular_shininess mt->layer[MATERIAL_CHANNEL_SPECULAR].value = 1.0f; // specular_shininess
@ -3888,13 +3901,21 @@ void model_set_renderstates(model_t *m) {
// Opaque pass // Opaque pass
renderstate_t *opaque_rs = &m->rs[RENDER_PASS_OPAQUE]; renderstate_t *opaque_rs = &m->rs[RENDER_PASS_OPAQUE];
{ {
opaque_rs->blend_enabled = 1; opaque_rs->blend_enabled = 0;
opaque_rs->blend_src = GL_SRC_ALPHA;
opaque_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA;
opaque_rs->cull_face_mode = GL_BACK; opaque_rs->cull_face_mode = GL_BACK;
opaque_rs->front_face = GL_CW; opaque_rs->front_face = GL_CW;
} }
// Transparent pass
renderstate_t *transparent_rs = &m->rs[RENDER_PASS_TRANSPARENT];
{
transparent_rs->blend_enabled = 1;
transparent_rs->blend_src = GL_SRC_ALPHA;
transparent_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA;
transparent_rs->cull_face_mode = GL_BACK;
transparent_rs->front_face = GL_CW;
}
// Shadow pass @todo // Shadow pass @todo
renderstate_t *shadow_rs = &m->rs[RENDER_PASS_SHADOW]; renderstate_t *shadow_rs = &m->rs[RENDER_PASS_SHADOW];
{ {
@ -4189,23 +4210,115 @@ void shader_colormap_model_internal(const char *col_name, const char *bool_name,
if( c.texture ) shader_texture( tex_name, *c.texture ); if( c.texture ) shader_texture( tex_name, *c.texture );
} }
typedef struct drawcall_t {
model_t *m;
int mesh;
union {
uint64_t order;
struct {
uint32_t tex;
float distance;
};
};
} drawcall_t;
static static
void model_draw_call(model_t m, int shader) { int drawcall_compare(const void *a, const void *b) {
const drawcall_t *da = a, *db = b;
return da->order < db->order ? 1 : da->order > db->order ? -1 : 0;
}
static
void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_mat) {
if(!m.iqm) return; if(!m.iqm) return;
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
handle old_shader = last_shader; handle old_shader = last_shader;
shader_bind(shader); shader_bind(shader);
renderstate_t *rs = &m.rs[RENDER_PASS_OPAQUE]; int rs_idx = model_getpass();
renderstate_t *rs = &m.rs[rs_idx];
renderstate_apply(rs);
glBindVertexArray( q->vao ); glBindVertexArray( q->vao );
struct iqmtriangle *tris = NULL; static array(int) required_rs = 0;
array_resize(required_rs, q->nummeshes);
for(int i = 0; i < q->nummeshes; i++) { for(int i = 0; i < q->nummeshes; i++) {
struct iqmmesh *im = &q->meshes[i]; struct iqmmesh *im = &q->meshes[i];
required_rs[i] = rs_idx;
if (required_rs[i] < RENDER_PASS_OVERRIDES_BEGIN) {
if (m.materials[i].layer[0].map.color.a < 1 || (m.materials[i].layer[0].map.texture && m.materials[i].layer[0].map.texture->transparent)) {
required_rs[i] = RENDER_PASS_TRANSPARENT;
}
if (m.shading == SHADING_PBR && (m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.color.a < 1 || (m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.texture && m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.texture->transparent))){
required_rs[i] = RENDER_PASS_TRANSPARENT;
}
}
}
static array(drawcall_t) drawcalls = 0;
array_resize(drawcalls, 0);
if (rs_idx > RENDER_PASS_OVERRIDES_BEGIN) {
for(int i = 0; i < q->nummeshes; i++) {
array_push(drawcalls, (drawcall_t){i, 0});
}
} else {
if(pass == -1 || pass == RENDER_PASS_OPAQUE) {
for(int i = 0; i < q->nummeshes; i++) {
// collect opaque drawcalls
if (required_rs[i] == RENDER_PASS_OPAQUE) {
drawcall_t call;
call.mesh = i;
call.tex = m.textures[i];
call.distance = -1;
if (m.shading == SHADING_PBR)
call.tex = m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.texture ? m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.texture->id : m.materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture ? m.materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture->id : texture_checker().id;
array_push(drawcalls, call);
}
}
}
if(pass == -1 || pass == RENDER_PASS_TRANSPARENT) {
for(int i = 0; i < q->nummeshes; i++) {
// collect transparent drawcalls
if (required_rs[i] == RENDER_PASS_TRANSPARENT) {
drawcall_t call;
call.mesh = i;
call.tex = m.textures[i];
// calculate distance from camera
// @todo: improve me, uses first mesh triangle
{
call.distance = len3(sub3(cam_pos, transform344(model_mat, m.meshcenters[i])));
}
if (m.shading == SHADING_PBR)
call.tex = m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.texture ? m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.texture->id : m.materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture ? m.materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture->id : texture_checker().id;
array_push(drawcalls, call);
}
}
}
}
// sort drawcalls by order
array_sort(drawcalls, drawcall_compare);
struct iqmtriangle *tris = NULL;
for(int di = 0; di < array_count(drawcalls); di++) {
int i = drawcalls[di].mesh;
struct iqmmesh *im = &q->meshes[i];
if (pass != -1 && pass != required_rs[i]) continue;
if (rs_idx != required_rs[i]) {
rs_idx = required_rs[i];
rs = &m.rs[rs_idx];
renderstate_apply(rs);
}
if (m.shading != SHADING_PBR) { if (m.shading != SHADING_PBR) {
shader_texture_unit("u_texture2d", q->textures[i], texture_unit()); shader_texture_unit("u_texture2d", q->textures[i], texture_unit());
@ -4244,7 +4357,7 @@ void model_draw_call(model_t m, int shader) {
shader_bind(old_shader); shader_bind(old_shader);
} }
void model_render_instanced(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count) { void model_render_instanced_pass(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count, int pass) {
if(!m.iqm) return; if(!m.iqm) return;
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
@ -4257,11 +4370,19 @@ void model_render_instanced(model_t m, mat44 proj, mat44 view, mat44* models, in
} }
model_set_uniforms(m, shader > 0 ? shader : m.program, mv, proj, view, models[0]); model_set_uniforms(m, shader > 0 ? shader : m.program, mv, proj, view, models[0]);
model_draw_call(m, shader > 0 ? shader : m.program); model_draw_call(m, shader > 0 ? shader : m.program, pass, pos44(view), models[0]);
}
void model_render_instanced(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count) {
model_render_instanced_pass(m, proj, view, models, shader, count, -1);
}
void model_render_pass(model_t m, mat44 proj, mat44 view, mat44 model, int shader, int pass) {
model_render_instanced_pass(m, proj, view, (mat44*)model, shader, 1, pass);
} }
void model_render(model_t m, mat44 proj, mat44 view, mat44 model, int shader) { void model_render(model_t m, mat44 proj, mat44 view, mat44 model, int shader) {
model_render_instanced(m, proj, view, (mat44*)model, shader, 1); model_render_pass(m, proj, view, model, shader, -1);
} }
static inline static inline
@ -4600,6 +4721,7 @@ void model_destroy(model_t m) {
FREE(m.texture_names[i]); FREE(m.texture_names[i]);
} }
array_free(m.texture_names); array_free(m.texture_names);
FREE(m.meshcenters);
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
// if(m.mesh) mesh_destroy(m.mesh); // if(m.mesh) mesh_destroy(m.mesh);
@ -4623,6 +4745,7 @@ unsigned model_getpass() {
unsigned model_setpass(unsigned pass) { unsigned model_setpass(unsigned pass) {
ASSERT(pass < NUM_RENDER_PASSES); ASSERT(pass < NUM_RENDER_PASSES);
ASSERT(pass != RENDER_PASS_OVERRIDES_BEGIN && pass != RENDER_PASS_OVERRIDES_END);
unsigned old_pass = model_renderpass; unsigned old_pass = model_renderpass;
model_renderpass = pass; model_renderpass = pass;
return old_pass; return old_pass;
@ -4688,6 +4811,7 @@ void lightmap_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm
unsigned old_pass = model_setpass(RENDER_PASS_LIGHTMAP); unsigned old_pass = model_setpass(RENDER_PASS_LIGHTMAP);
for (int b = 0; b < bounces; b++) { for (int b = 0; b < bounces; b++) {
model_setpass(RENDER_PASS_LIGHTMAP);
for (int i = 0; i < array_count(lm->models); i++) { for (int i = 0; i < array_count(lm->models); i++) {
model_t *m = lm->models[i]; model_t *m = lm->models[i];
if (!m->lmdata) { if (!m->lmdata) {

View File

@ -608,8 +608,13 @@ enum SHADING_MODE {
enum RENDER_PASS { enum RENDER_PASS {
RENDER_PASS_OPAQUE, RENDER_PASS_OPAQUE,
RENDER_PASS_TRANSPARENT,
RENDER_PASS_OVERRIDES_BEGIN,
RENDER_PASS_SHADOW, RENDER_PASS_SHADOW,
RENDER_PASS_LIGHTMAP, RENDER_PASS_LIGHTMAP,
RENDER_PASS_CUSTOM, // make sure to apply renderstate before calling this
RENDER_PASS_OVERRIDES_END,
NUM_RENDER_PASSES NUM_RENDER_PASSES
}; };
@ -670,6 +675,7 @@ typedef struct model_t {
void *verts; void *verts;
int num_verts; int num_verts;
void *tris; void *tris;
vec3 *meshcenters;
int num_tris; int num_tris;
handle vao, ibo, vbo, vao_instanced; handle vao, ibo, vbo, vao_instanced;
@ -710,6 +716,8 @@ API void model_skybox(model_t*, skybox_t sky, bool load_sh);
API void model_render(model_t, mat44 proj, mat44 view, mat44 model, int shader); API void model_render(model_t, mat44 proj, mat44 view, mat44 model, int shader);
API void model_render_skeleton(model_t, mat44 model); API void model_render_skeleton(model_t, mat44 model);
API void model_render_instanced(model_t, mat44 proj, mat44 view, mat44 *models, int shader, unsigned count); API void model_render_instanced(model_t, mat44 proj, mat44 view, mat44 *models, int shader, unsigned count);
API void model_render_instanced_pass(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count, int pass);
API void model_render_pass(model_t m, mat44 proj, mat44 view, mat44 model, int shader, int pass);
API void model_set_texture(model_t, texture_t t); API void model_set_texture(model_t, texture_t t);
API bool model_get_bone_pose(model_t m, unsigned joint, mat34 *out); API bool model_get_bone_pose(model_t m, unsigned joint, mat34 *out);
API void model_destroy(model_t); API void model_destroy(model_t);

View File

@ -12620,6 +12620,20 @@ void lookat44(mat44 m, vec3 eye, vec3 center, vec3 up) {
m[ 8] = r.z; m[ 9] = u.z; m[10] = -f.z; m[11] = 0; m[ 8] = r.z; m[ 9] = u.z; m[10] = -f.z; m[11] = 0;
m[12] = -dot3(r, eye); m[13] = -dot3(u, eye); m[14] = dot3(f, eye); m[15] = 1; m[12] = -dot3(r, eye); m[13] = -dot3(u, eye); m[14] = dot3(f, eye); m[15] = 1;
} }
vec3 pos44(mat44 m) {
vec3 position;
// The camera position is the negation of the translation vector
// transformed by the inverse of the rotation matrix.
// Since the upper-left 3x3 part of the view matrix is orthogonal,
// its inverse is equal to its transpose.
position.x = -(m[0] * m[12] + m[1] * m[13] + m[2] * m[14]);
position.y = -(m[4] * m[12] + m[5] * m[13] + m[6] * m[14]);
position.z = -(m[8] * m[12] + m[9] * m[13] + m[10] * m[14]);
return position;
}
// --- // ---
void translation44(mat44 m, float x, float y, float z) { // identity4 + translate4 void translation44(mat44 m, float x, float y, float z) { // identity4 + translate4
m[ 0] = 1.0f; m[ 1] = 0.0f; m[ 2] = 0.0f; m[ 3] = 0.0f; m[ 0] = 1.0f; m[ 1] = 0.0f; m[ 2] = 0.0f; m[ 3] = 0.0f;
@ -17759,6 +17773,16 @@ max_aniso = 4;
t->n = n; t->n = n;
t->flags = flags; t->flags = flags;
t->filename = t->filename ? t->filename : ""; t->filename = t->filename ? t->filename : "";
t->transparent = 0;
if (t->n == 4 && pixels) {
for (int i = 0; i < w * h; i++) {
if (((uint8_t *)pixels)[i * 4 + 3] < 255) {
t->transparent = 1;
break;
}
}
}
return t->id; return t->id;
} }
@ -17767,7 +17791,6 @@ texture_t texture_create(unsigned w, unsigned h, unsigned n, const void *pixels,
texture_t texture = {0}; texture_t texture = {0};
glGenTextures( 1, &texture.id ); glGenTextures( 1, &texture.id );
texture_update( &texture, w, h, n, pixels, flags ); texture_update( &texture, w, h, n, pixels, flags );
texture.transparent = texture.n > 3; // @fixme: should be true only if any pixel.a == 0
return texture; return texture;
} }
@ -20071,12 +20094,12 @@ void model_set_uniforms(model_t m, int shader, mat44 mv, mat44 proj, mat44 view,
glUniformMatrix4fv( loc, 1, GL_FALSE, vp); glUniformMatrix4fv( loc, 1, GL_FALSE, vp);
} }
if( (loc = glGetUniformLocation(shader, "u_cam_pos")) >= 0 ) { if( (loc = glGetUniformLocation(shader, "u_cam_pos")) >= 0 ) {
vec3 pos = vec3(view[12], view[13], view[14]); vec3 pos = pos44(view);
glUniform3fv( loc, 1, &pos.x ); glUniform3fv( loc, 1, &pos.x );
} }
else else
if( (loc = glGetUniformLocation(shader, "cam_pos")) >= 0 ) { if( (loc = glGetUniformLocation(shader, "cam_pos")) >= 0 ) {
vec3 pos = vec3(view[12], view[13], view[14]); vec3 pos = pos44(view);
glUniform3fv( loc, 1, &pos.x ); glUniform3fv( loc, 1, &pos.x );
} }
if( (loc = glGetUniformLocation(shader, "u_cam_dir")) >= 0 ) { if( (loc = glGetUniformLocation(shader, "u_cam_dir")) >= 0 ) {
@ -20377,9 +20400,13 @@ bool model_load_meshes(iqm_t *q, const struct iqmheader *hdr, model_t *m) {
q->textures = CALLOC(hdr->num_meshes * 8, sizeof(GLuint)); q->textures = CALLOC(hdr->num_meshes * 8, sizeof(GLuint));
q->colormaps = CALLOC(hdr->num_meshes * 8, sizeof(vec4)); q->colormaps = CALLOC(hdr->num_meshes * 8, sizeof(vec4));
m->meshcenters = CALLOC(hdr->num_meshes, sizeof(vec3));
for(int i = 0; i < (int)hdr->num_meshes; i++) { for(int i = 0; i < (int)hdr->num_meshes; i++) {
int invalid = texture_checker().id; int invalid = texture_checker().id;
q->textures[i] = invalid; q->textures[i] = invalid;
GLfloat *pos = verts[q->meshes[i].first_vertex].position;
m->meshcenters[i] = vec3(pos[0], pos[1], pos[2]);
} }
const char *str = hdr->ofs_text ? (char *)&q->buf[hdr->ofs_text] : ""; const char *str = hdr->ofs_text ? (char *)&q->buf[hdr->ofs_text] : "";
@ -20473,7 +20500,7 @@ void model_load_pbr_layer(material_layer_t *layer, const char *texname, bool loa
static static
void model_load_pbr(material_t *mt) { void model_load_pbr(material_t *mt) {
// initialise default colors // initialise default colors
mt->layer[MATERIAL_CHANNEL_DIFFUSE].map.color = vec4(0.5,0.5,0.5,0.5); mt->layer[MATERIAL_CHANNEL_DIFFUSE].map.color = vec4(0.5,0.5,0.5,1.0);
mt->layer[MATERIAL_CHANNEL_NORMALS].map.color = vec4(0,0,0,0); mt->layer[MATERIAL_CHANNEL_NORMALS].map.color = vec4(0,0,0,0);
mt->layer[MATERIAL_CHANNEL_SPECULAR].map.color = vec4(0,0,0,0); mt->layer[MATERIAL_CHANNEL_SPECULAR].map.color = vec4(0,0,0,0);
mt->layer[MATERIAL_CHANNEL_SPECULAR].value = 1.0f; // specular_shininess mt->layer[MATERIAL_CHANNEL_SPECULAR].value = 1.0f; // specular_shininess
@ -20673,13 +20700,21 @@ void model_set_renderstates(model_t *m) {
// Opaque pass // Opaque pass
renderstate_t *opaque_rs = &m->rs[RENDER_PASS_OPAQUE]; renderstate_t *opaque_rs = &m->rs[RENDER_PASS_OPAQUE];
{ {
opaque_rs->blend_enabled = 1; opaque_rs->blend_enabled = 0;
opaque_rs->blend_src = GL_SRC_ALPHA;
opaque_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA;
opaque_rs->cull_face_mode = GL_BACK; opaque_rs->cull_face_mode = GL_BACK;
opaque_rs->front_face = GL_CW; opaque_rs->front_face = GL_CW;
} }
// Transparent pass
renderstate_t *transparent_rs = &m->rs[RENDER_PASS_TRANSPARENT];
{
transparent_rs->blend_enabled = 1;
transparent_rs->blend_src = GL_SRC_ALPHA;
transparent_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA;
transparent_rs->cull_face_mode = GL_BACK;
transparent_rs->front_face = GL_CW;
}
// Shadow pass @todo // Shadow pass @todo
renderstate_t *shadow_rs = &m->rs[RENDER_PASS_SHADOW]; renderstate_t *shadow_rs = &m->rs[RENDER_PASS_SHADOW];
{ {
@ -20974,23 +21009,115 @@ void shader_colormap_model_internal(const char *col_name, const char *bool_name,
if( c.texture ) shader_texture( tex_name, *c.texture ); if( c.texture ) shader_texture( tex_name, *c.texture );
} }
typedef struct drawcall_t {
model_t *m;
int mesh;
union {
uint64_t order;
struct {
uint32_t tex;
float distance;
};
};
} drawcall_t;
static static
void model_draw_call(model_t m, int shader) { int drawcall_compare(const void *a, const void *b) {
const drawcall_t *da = a, *db = b;
return da->order < db->order ? 1 : da->order > db->order ? -1 : 0;
}
static
void model_draw_call(model_t m, int shader, int pass, vec3 cam_pos, mat44 model_mat) {
if(!m.iqm) return; if(!m.iqm) return;
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
handle old_shader = last_shader; handle old_shader = last_shader;
shader_bind(shader); shader_bind(shader);
renderstate_t *rs = &m.rs[RENDER_PASS_OPAQUE]; int rs_idx = model_getpass();
renderstate_t *rs = &m.rs[rs_idx];
renderstate_apply(rs);
glBindVertexArray( q->vao ); glBindVertexArray( q->vao );
struct iqmtriangle *tris = NULL; static array(int) required_rs = 0;
array_resize(required_rs, q->nummeshes);
for(int i = 0; i < q->nummeshes; i++) { for(int i = 0; i < q->nummeshes; i++) {
struct iqmmesh *im = &q->meshes[i]; struct iqmmesh *im = &q->meshes[i];
required_rs[i] = rs_idx;
if (required_rs[i] < RENDER_PASS_OVERRIDES_BEGIN) {
if (m.materials[i].layer[0].map.color.a < 1 || (m.materials[i].layer[0].map.texture && m.materials[i].layer[0].map.texture->transparent)) {
required_rs[i] = RENDER_PASS_TRANSPARENT;
}
if (m.shading == SHADING_PBR && (m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.color.a < 1 || (m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.texture && m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.texture->transparent))){
required_rs[i] = RENDER_PASS_TRANSPARENT;
}
}
}
static array(drawcall_t) drawcalls = 0;
array_resize(drawcalls, 0);
if (rs_idx > RENDER_PASS_OVERRIDES_BEGIN) {
for(int i = 0; i < q->nummeshes; i++) {
array_push(drawcalls, (drawcall_t){i, 0});
}
} else {
if(pass == -1 || pass == RENDER_PASS_OPAQUE) {
for(int i = 0; i < q->nummeshes; i++) {
// collect opaque drawcalls
if (required_rs[i] == RENDER_PASS_OPAQUE) {
drawcall_t call;
call.mesh = i;
call.tex = m.textures[i];
call.distance = -1;
if (m.shading == SHADING_PBR)
call.tex = m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.texture ? m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.texture->id : m.materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture ? m.materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture->id : texture_checker().id;
array_push(drawcalls, call);
}
}
}
if(pass == -1 || pass == RENDER_PASS_TRANSPARENT) {
for(int i = 0; i < q->nummeshes; i++) {
// collect transparent drawcalls
if (required_rs[i] == RENDER_PASS_TRANSPARENT) {
drawcall_t call;
call.mesh = i;
call.tex = m.textures[i];
// calculate distance from camera
// @todo: improve me, uses first mesh triangle
{
call.distance = len3(sub3(cam_pos, transform344(model_mat, m.meshcenters[i])));
}
if (m.shading == SHADING_PBR)
call.tex = m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.texture ? m.materials[i].layer[MATERIAL_CHANNEL_ALBEDO].map.texture->id : m.materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture ? m.materials[i].layer[MATERIAL_CHANNEL_DIFFUSE].map.texture->id : texture_checker().id;
array_push(drawcalls, call);
}
}
}
}
// sort drawcalls by order
array_sort(drawcalls, drawcall_compare);
struct iqmtriangle *tris = NULL;
for(int di = 0; di < array_count(drawcalls); di++) {
int i = drawcalls[di].mesh;
struct iqmmesh *im = &q->meshes[i];
if (pass != -1 && pass != required_rs[i]) continue;
if (rs_idx != required_rs[i]) {
rs_idx = required_rs[i];
rs = &m.rs[rs_idx];
renderstate_apply(rs);
}
if (m.shading != SHADING_PBR) { if (m.shading != SHADING_PBR) {
shader_texture_unit("u_texture2d", q->textures[i], texture_unit()); shader_texture_unit("u_texture2d", q->textures[i], texture_unit());
@ -21029,7 +21156,7 @@ void model_draw_call(model_t m, int shader) {
shader_bind(old_shader); shader_bind(old_shader);
} }
void model_render_instanced(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count) { void model_render_instanced_pass(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count, int pass) {
if(!m.iqm) return; if(!m.iqm) return;
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
@ -21042,11 +21169,19 @@ void model_render_instanced(model_t m, mat44 proj, mat44 view, mat44* models, in
} }
model_set_uniforms(m, shader > 0 ? shader : m.program, mv, proj, view, models[0]); model_set_uniforms(m, shader > 0 ? shader : m.program, mv, proj, view, models[0]);
model_draw_call(m, shader > 0 ? shader : m.program); model_draw_call(m, shader > 0 ? shader : m.program, pass, pos44(view), models[0]);
}
void model_render_instanced(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count) {
model_render_instanced_pass(m, proj, view, models, shader, count, -1);
}
void model_render_pass(model_t m, mat44 proj, mat44 view, mat44 model, int shader, int pass) {
model_render_instanced_pass(m, proj, view, (mat44*)model, shader, 1, pass);
} }
void model_render(model_t m, mat44 proj, mat44 view, mat44 model, int shader) { void model_render(model_t m, mat44 proj, mat44 view, mat44 model, int shader) {
model_render_instanced(m, proj, view, (mat44*)model, shader, 1); model_render_pass(m, proj, view, model, shader, -1);
} }
static inline static inline
@ -21385,6 +21520,7 @@ void model_destroy(model_t m) {
FREE(m.texture_names[i]); FREE(m.texture_names[i]);
} }
array_free(m.texture_names); array_free(m.texture_names);
FREE(m.meshcenters);
iqm_t *q = m.iqm; iqm_t *q = m.iqm;
// if(m.mesh) mesh_destroy(m.mesh); // if(m.mesh) mesh_destroy(m.mesh);
@ -21408,6 +21544,7 @@ unsigned model_getpass() {
unsigned model_setpass(unsigned pass) { unsigned model_setpass(unsigned pass) {
ASSERT(pass < NUM_RENDER_PASSES); ASSERT(pass < NUM_RENDER_PASSES);
ASSERT(pass != RENDER_PASS_OVERRIDES_BEGIN && pass != RENDER_PASS_OVERRIDES_END);
unsigned old_pass = model_renderpass; unsigned old_pass = model_renderpass;
model_renderpass = pass; model_renderpass = pass;
return old_pass; return old_pass;
@ -21473,6 +21610,7 @@ void lightmap_bake(lightmap_t *lm, int bounces, void (*drawscene)(lightmap_t *lm
unsigned old_pass = model_setpass(RENDER_PASS_LIGHTMAP); unsigned old_pass = model_setpass(RENDER_PASS_LIGHTMAP);
for (int b = 0; b < bounces; b++) { for (int b = 0; b < bounces; b++) {
model_setpass(RENDER_PASS_LIGHTMAP);
for (int i = 0; i < array_count(lm->models); i++) { for (int i = 0; i < array_count(lm->models); i++) {
model_t *m = lm->models[i]; model_t *m = lm->models[i];
if (!m->lmdata) { if (!m->lmdata) {

View File

@ -1202,6 +1202,7 @@ API void ortho44(mat44 m, float l, float r, float b, float t, float n, float f);
API void frustum44(mat44 m, float l, float r, float b, float t, float n, float f); API void frustum44(mat44 m, float l, float r, float b, float t, float n, float f);
API void perspective44(mat44 m, float fovy_degrees, float aspect, float nearp, float farp); API void perspective44(mat44 m, float fovy_degrees, float aspect, float nearp, float farp);
API void lookat44(mat44 m, vec3 eye, vec3 center, vec3 up); API void lookat44(mat44 m, vec3 eye, vec3 center, vec3 up);
API vec3 pos44(mat44 m);
// --- // ---
API void translation44(mat44 m, float x, float y, float z); API void translation44(mat44 m, float x, float y, float z);
API void translate44(mat44 m, float x, float y, float z); API void translate44(mat44 m, float x, float y, float z);
@ -3642,8 +3643,13 @@ enum SHADING_MODE {
enum RENDER_PASS { enum RENDER_PASS {
RENDER_PASS_OPAQUE, RENDER_PASS_OPAQUE,
RENDER_PASS_TRANSPARENT,
RENDER_PASS_OVERRIDES_BEGIN,
RENDER_PASS_SHADOW, RENDER_PASS_SHADOW,
RENDER_PASS_LIGHTMAP, RENDER_PASS_LIGHTMAP,
RENDER_PASS_CUSTOM, // make sure to apply renderstate before calling this
RENDER_PASS_OVERRIDES_END,
NUM_RENDER_PASSES NUM_RENDER_PASSES
}; };
@ -3704,6 +3710,7 @@ typedef struct model_t {
void *verts; void *verts;
int num_verts; int num_verts;
void *tris; void *tris;
vec3 *meshcenters;
int num_tris; int num_tris;
handle vao, ibo, vbo, vao_instanced; handle vao, ibo, vbo, vao_instanced;
@ -3744,6 +3751,8 @@ API void model_skybox(model_t*, skybox_t sky, bool load_sh);
API void model_render(model_t, mat44 proj, mat44 view, mat44 model, int shader); API void model_render(model_t, mat44 proj, mat44 view, mat44 model, int shader);
API void model_render_skeleton(model_t, mat44 model); API void model_render_skeleton(model_t, mat44 model);
API void model_render_instanced(model_t, mat44 proj, mat44 view, mat44 *models, int shader, unsigned count); API void model_render_instanced(model_t, mat44 proj, mat44 view, mat44 *models, int shader, unsigned count);
API void model_render_instanced_pass(model_t m, mat44 proj, mat44 view, mat44* models, int shader, unsigned count, int pass);
API void model_render_pass(model_t m, mat44 proj, mat44 view, mat44 model, int shader, int pass);
API void model_set_texture(model_t, texture_t t); API void model_set_texture(model_t, texture_t t);
API bool model_get_bone_pose(model_t m, unsigned joint, mat34 *out); API bool model_get_bone_pose(model_t m, unsigned joint, mat34 *out);
API void model_destroy(model_t); API void model_destroy(model_t);