diff --git a/ref/vk/shaders/additive.rahit b/ref/vk/shaders/additive.rahit index ab9a7eb2..973074c1 100644 --- a/ref/vk/shaders/additive.rahit +++ b/ref/vk/shaders/additive.rahit @@ -24,7 +24,7 @@ void main() { const uint vi2 = uint(getIndex(first_index_offset+1)) + getKusok(kusok_index).vertex_offset; const uint vi3 = uint(getIndex(first_index_offset+2)) + getKusok(kusok_index).vertex_offset; - const vec2 texture_uv = getVertex(vi1).gl_tc * (1. - bary.x - bary.y) + getVertex(vi2).gl_tc * bary.x + getVertex(vi3).gl_tc * bary.y + push_constants.time * getKusok(kusok_index).uv_speed; + const vec2 texture_uv = GET_VERTEX(vi1).gl_tc * (1. - bary.x - bary.y) + GET_VERTEX(vi2).gl_tc * bary.x + GET_VERTEX(vi3).gl_tc * bary.y + push_constants.time * getKusok(kusok_index).uv_speed; // TODO mips const uint tex_index = getKusok(kusok_index).tex_base_color; const vec4 texture_color = texture(textures[nonuniformEXT(tex_index)], texture_uv); diff --git a/ref/vk/shaders/alphamask.rahit b/ref/vk/shaders/alphamask.rahit index f2d07213..59ae5a46 100644 --- a/ref/vk/shaders/alphamask.rahit +++ b/ref/vk/shaders/alphamask.rahit @@ -18,7 +18,7 @@ void main() { const uint vi2 = uint(getIndex(first_index_offset+1)) + getKusok(kusok_index).vertex_offset; const uint vi3 = uint(getIndex(first_index_offset+2)) + getKusok(kusok_index).vertex_offset; - const vec2 texture_uv = getVertex(vi1).gl_tc * (1. - bary.x - bary.y) + getVertex(vi2).gl_tc * bary.x + getVertex(vi3).gl_tc * bary.y; + const vec2 texture_uv = GET_VERTEX(vi1).gl_tc * (1. - bary.x - bary.y) + GET_VERTEX(vi2).gl_tc * bary.x + GET_VERTEX(vi3).gl_tc * bary.y; const uint tex_index = getKusok(kusok_index).tex_base_color; const vec4 texture_color = texture(textures[nonuniformEXT(tex_index)], texture_uv); diff --git a/ref/vk/shaders/brush.frag b/ref/vk/shaders/brush.frag index a9c87ef8..b87b7950 100644 --- a/ref/vk/shaders/brush.frag +++ b/ref/vk/shaders/brush.frag @@ -21,28 +21,23 @@ layout(location=1) in vec3 vNormal; layout(location=2) in vec2 vTexture0; layout(location=3) in vec2 vLightmapUV; layout(location=4) in vec4 vColor; -layout(location=5) flat in uint vFlags; layout(location=0) out vec4 outColor; // FIXME what should this be? const float dlight_attenuation_const = 5000.; -#define FLAG_VERTEX_LIGHTING 1 - void main() { outColor = vec4(0.); - const vec4 baseColor = vColor * texture(sTexture0, vTexture0); + const vec4 tex_color = texture(sTexture0, vTexture0); + // TODO make sure textures are premultiplied alpha + const vec4 baseColor = vColor * tex_color; if (baseColor.a < alpha_test_threshold) discard; outColor.a = baseColor.a; - - if ((vFlags & FLAG_VERTEX_LIGHTING) == 0) - outColor.rgb += baseColor.rgb * texture(sLightmap, vLightmapUV).rgb; - else - outColor.rgb += baseColor.rgb; + outColor.rgb += baseColor.rgb * texture(sLightmap, vLightmapUV).rgb; for (uint i = 0; i < ubo.num_lights; ++i) { const vec4 light_pos_r = ubo.lights[i].pos_r; diff --git a/ref/vk/shaders/brush.vert b/ref/vk/shaders/brush.vert index 573d8732..86d045fe 100644 --- a/ref/vk/shaders/brush.vert +++ b/ref/vk/shaders/brush.vert @@ -10,27 +10,18 @@ layout(location=1) in vec3 aNormal; layout(location=2) in vec2 aTexture0; layout(location=3) in vec2 aLightmapUV; layout(location=4) in vec4 aLightColor; -layout(location=5) in uint aFlags; layout(location=0) out vec3 vPos; layout(location=1) out vec3 vNormal; layout(location=2) out vec2 vTexture0; layout(location=3) out vec2 vLightmapUV; layout(location=4) out vec4 vColor; -layout(location=5) flat out uint vFlags; - -#define FLAG_VERTEX_LIGHTING 1 void main() { vPos = aPos.xyz; vNormal = aNormal; vTexture0 = aTexture0; vLightmapUV = aLightmapUV; - vColor = ubo.color; - - if ((aFlags & FLAG_VERTEX_LIGHTING) != 0) - vColor *= aLightColor; - - vFlags = aFlags; + vColor = ubo.color * aLightColor; gl_Position = ubo.mvp * vec4(aPos.xyz, 1.); } diff --git a/ref/vk/shaders/light_common.glsl b/ref/vk/shaders/light_common.glsl index ee2cba92..dbfb7b16 100644 --- a/ref/vk/shaders/light_common.glsl +++ b/ref/vk/shaders/light_common.glsl @@ -53,9 +53,9 @@ bool shadowTestAlphaMask(vec3 pos, vec3 dir, float dist) { const uint vi2 = uint(getIndex(first_index_offset+1)) + kusok.vertex_offset; const uint vi3 = uint(getIndex(first_index_offset+2)) + kusok.vertex_offset; const vec2 uvs[3] = { - getVertex(vi1).gl_tc, - getVertex(vi2).gl_tc, - getVertex(vi3).gl_tc, + GET_VERTEX(vi1).gl_tc, + GET_VERTEX(vi2).gl_tc, + GET_VERTEX(vi3).gl_tc, }; const vec2 bary = rayQueryGetIntersectionBarycentricsEXT(rq, false); const vec2 uv = baryMix(uvs[0], uvs[1], uvs[2], bary); diff --git a/ref/vk/shaders/ray_kusochki.glsl b/ref/vk/shaders/ray_kusochki.glsl index 9ae612b9..af0110fe 100644 --- a/ref/vk/shaders/ray_kusochki.glsl +++ b/ref/vk/shaders/ray_kusochki.glsl @@ -1,7 +1,6 @@ #ifndef RAY_KUSOCHKI_GLSL_INCLUDED #define RAY_KUSOCHKI_GLSL_INCLUDED #extension GL_EXT_shader_16bit_storage : require -//#extension GL_EXT_shader_8bit_storage : require #define GLSL #include "ray_interop.h" @@ -14,10 +13,7 @@ struct Vertex { vec3 tangent; vec2 gl_tc; vec2 _unused_lm_tc; - - //float padding; - //uint8_t color[4]; - uint _unused_color_u8_4; + uint color; }; layout(std430, binding = 3, set = 0) readonly buffer Kusochki { Kusok a[]; } kusochki; @@ -26,6 +22,6 @@ layout(std430, binding = 5, set = 0) readonly buffer Vertices { Vertex a[]; } ve Kusok getKusok(uint index) { return kusochki.a[index]; } uint16_t getIndex(uint index) { return indices.a[index]; } -Vertex getVertex(uint index) { return vertices.a[index]; } +#define GET_VERTEX(index) (vertices.a[index]) #endif //ifndef RAY_KUSOCHKI_GLSL_INCLUDED diff --git a/ref/vk/shaders/rt_geometry.glsl b/ref/vk/shaders/rt_geometry.glsl index 87b42e72..c2274f81 100644 --- a/ref/vk/shaders/rt_geometry.glsl +++ b/ref/vk/shaders/rt_geometry.glsl @@ -83,21 +83,21 @@ Geometry readHitGeometry(vec2 bary, float ray_cone_width) { const uint vi3 = uint(getIndex(first_index_offset+2)) + kusok.vertex_offset; const vec3 pos[3] = { - objectToWorld * vec4(getVertex(vi1).pos, 1.f), - objectToWorld * vec4(getVertex(vi2).pos, 1.f), - objectToWorld * vec4(getVertex(vi3).pos, 1.f), + objectToWorld * vec4(GET_VERTEX(vi1).pos, 1.f), + objectToWorld * vec4(GET_VERTEX(vi2).pos, 1.f), + objectToWorld * vec4(GET_VERTEX(vi3).pos, 1.f), }; const vec3 prev_pos[3] = { - (kusok.prev_transform * vec4(getVertex(vi1).prev_pos, 1.f)).xyz, - (kusok.prev_transform * vec4(getVertex(vi2).prev_pos, 1.f)).xyz, - (kusok.prev_transform * vec4(getVertex(vi3).prev_pos, 1.f)).xyz, + (kusok.prev_transform * vec4(GET_VERTEX(vi1).prev_pos, 1.f)).xyz, + (kusok.prev_transform * vec4(GET_VERTEX(vi2).prev_pos, 1.f)).xyz, + (kusok.prev_transform * vec4(GET_VERTEX(vi3).prev_pos, 1.f)).xyz, }; const vec2 uvs[3] = { - getVertex(vi1).gl_tc, - getVertex(vi2).gl_tc, - getVertex(vi3).gl_tc, + GET_VERTEX(vi1).gl_tc, + GET_VERTEX(vi2).gl_tc, + GET_VERTEX(vi3).gl_tc, }; geom.pos = baryMix(pos[0], pos[1], pos[2], bary); @@ -111,14 +111,14 @@ Geometry readHitGeometry(vec2 bary, float ray_cone_width) { // NOTE: only support rotations, for arbitrary transform would need to do transpose(inverse(mat3(gl_ObjectToWorldEXT))) const mat3 normalTransform = mat3(objectToWorld); // mat3(gl_ObjectToWorldEXT); geom.normal_shading = normalize(normalTransform * baryMix( - getVertex(vi1).normal, - getVertex(vi2).normal, - getVertex(vi3).normal, + GET_VERTEX(vi1).normal, + GET_VERTEX(vi2).normal, + GET_VERTEX(vi3).normal, bary)); geom.tangent = normalize(normalTransform * baryMix( - getVertex(vi1).tangent, - getVertex(vi2).tangent, - getVertex(vi3).tangent, + GET_VERTEX(vi1).tangent, + GET_VERTEX(vi2).tangent, + GET_VERTEX(vi3).tangent, bary)); geom.uv_lods = computeAnisotropicEllipseAxes(geom.pos, geom.normal_geometry, ray_direction, ray_cone_width * hit_t, pos, uvs, geom.uv); @@ -130,6 +130,7 @@ Geometry readHitGeometry(vec2 bary, float ray_cone_width) { struct MiniGeometry { vec2 uv; uint kusok_index; + vec4 color; }; MiniGeometry readCandidateMiniGeometry(rayQueryEXT rq) { @@ -144,16 +145,23 @@ MiniGeometry readCandidateMiniGeometry(rayQueryEXT rq) { const uint vi2 = uint(getIndex(first_index_offset+1)) + kusok.vertex_offset; const uint vi3 = uint(getIndex(first_index_offset+2)) + kusok.vertex_offset; const vec2 uvs[3] = { - getVertex(vi1).gl_tc, - getVertex(vi2).gl_tc, - getVertex(vi3).gl_tc, + GET_VERTEX(vi1).gl_tc, + GET_VERTEX(vi2).gl_tc, + GET_VERTEX(vi3).gl_tc, }; const vec2 bary = rayQueryGetIntersectionBarycentricsEXT(rq, false); const vec2 uv = baryMix(uvs[0], uvs[1], uvs[2], bary); + const vec4 colors[3] = { + unpackUnorm4x8(GET_VERTEX(vi1).color), + unpackUnorm4x8(GET_VERTEX(vi2).color), + unpackUnorm4x8(GET_VERTEX(vi3).color), + }; + MiniGeometry ret; ret.uv = uv; ret.kusok_index = kusok_index; + ret.color = baryMix(colors[0], colors[1], colors[2], bary); return ret; } #endif // #ifdef RAY_QUERY diff --git a/ref/vk/shaders/trace_additive.glsl b/ref/vk/shaders/trace_additive.glsl index 05c7a274..ddc22116 100644 --- a/ref/vk/shaders/trace_additive.glsl +++ b/ref/vk/shaders/trace_additive.glsl @@ -13,10 +13,10 @@ vec3 traceAdditive(vec3 pos, vec3 dir, float L) { rayQueryInitializeEXT(rq, tlas, flags, GEOMETRY_BIT_ADDITIVE, pos, 0., dir, L + additive_soft_overshoot); while (rayQueryProceedEXT(rq)) { const MiniGeometry geom = readCandidateMiniGeometry(rq); - const uint tex_base_color = getKusok(geom.kusok_index).tex_base_color; - const vec4 texture_color = texture(textures[nonuniformEXT(tex_base_color)], geom.uv); const Kusok kusok = getKusok(geom.kusok_index); - const vec3 color = texture_color.rgb * kusok.emissive * texture_color.a * kusok.color.a; + + const vec4 texture_color = texture(textures[nonuniformEXT(kusok.tex_base_color)], geom.uv); + const vec3 color = texture_color.rgb * kusok.emissive * texture_color.a * kusok.color.a * SRGBtoLINEAR(geom.color.rgb * geom.color.a); const float hit_t = rayQueryGetIntersectionTEXT(rq, false); const float overshoot = hit_t - L; diff --git a/ref/vk/shaders/utils.glsl b/ref/vk/shaders/utils.glsl index d06d55af..7c6a2a51 100644 --- a/ref/vk/shaders/utils.glsl +++ b/ref/vk/shaders/utils.glsl @@ -30,12 +30,15 @@ vec3 normalDecode( vec2 f ) return normalize( n ); } -vec3 baryMix(vec3 v1, vec3 v2, vec3 v3, vec2 bary) { - return v1 * (1. - bary.x - bary.y) + v2 * bary.x + v3 * bary.y; -} - vec2 baryMix(vec2 v1, vec2 v2, vec2 v3, vec2 bary) { return v1 * (1. - bary.x - bary.y) + v2 * bary.x + v3 * bary.y; } +vec3 baryMix(vec3 v1, vec3 v2, vec3 v3, vec2 bary) { + return v1 * (1. - bary.x - bary.y) + v2 * bary.x + v3 * bary.y; +} + +vec4 baryMix(vec4 v1, vec4 v2, vec4 v3, vec2 bary) { + return v1 * (1. - bary.x - bary.y) + v2 * bary.x + v3 * bary.y; +} #endif // UTILS_GLSL_INCLUDED diff --git a/ref/vk/vk_beams.c b/ref/vk/vk_beams.c index e099c53f..1de632d1 100644 --- a/ref/vk/vk_beams.c +++ b/ref/vk/vk_beams.c @@ -7,6 +7,7 @@ #include "vk_sprite.h" #include "vk_scene.h" #include "vk_math.h" +#include "vk_triapi.h" #include "xash3d_types.h" #include "xash3d_mathlib.h" @@ -145,13 +146,20 @@ qboolean R_BeamCull( const vec3_t start, const vec3_t end, qboolean pvsOnly ) return true; } +static float clampf(float v, float min, float max) { + if (v < min) return min; + if (v > max) return max; + return v; +} -static void applyBrightness( float brightness, const vec4_t color, vec4_t out ) -{ - out[0] = color[0] * color[3] * brightness; - out[1] = color[1] * color[3] * brightness; - out[2] = color[2] * color[3] * brightness; - out[3] = 1.f; +// FIXME unclear how to organize this +static void applyBrightness( float brightness, rgba_t out ) { + out[0] = out[1] = out[2] = clampf(brightness, 0, 1) * 255.f; + out[3] = 255; +} + +static void TriBrightness( float brightness ) { + TriColor4f( brightness, brightness, brightness, 1.f ); } static void R_DrawSegs( vec3_t source, vec3_t delta, float width, float scale, float freq, float speed, int segments, int flags, const vec4_t color, int texture, int render_mode ) @@ -298,8 +306,7 @@ static void R_DrawSegs( vec3_t source, vec3_t delta, float width, float scale, f dst_vtx->lm_tc[0] = dst_vtx->lm_tc[1] = 0.f; dst_vtx->gl_tc[0] = 0.0f; dst_vtx->gl_tc[1] = curSeg.texcoord; - //FIXME VK applyBrightness( brightness, color, dst_vtx->color ); - // FIXME VK pglNormal3fv( vAveNormal ); + applyBrightness( brightness, dst_vtx->color ); VectorCopy( vPoint1, dst_vtx->pos ); VectorCopy( vAveNormal, dst_vtx->normal ); ++dst_vtx; @@ -307,9 +314,9 @@ static void R_DrawSegs( vec3_t source, vec3_t delta, float width, float scale, f dst_vtx->lm_tc[0] = dst_vtx->lm_tc[1] = 0.f; dst_vtx->gl_tc[0] = 1.0f; dst_vtx->gl_tc[1] = curSeg.texcoord; - //FIXME VK applyBrightness( brightness, color, dst_vtx->color ); - // FIXME VK pglNormal3fv( vAveNormal ); + applyBrightness( brightness, dst_vtx->color ); VectorCopy( vPoint2, dst_vtx->pos ); + VectorCopy( vAveNormal, dst_vtx->normal ); ++dst_vtx; } @@ -339,17 +346,17 @@ static void R_DrawSegs( vec3_t source, vec3_t delta, float width, float scale, f dst_vtx->lm_tc[0] = dst_vtx->lm_tc[1] = 0.f; dst_vtx->gl_tc[0] = 0.0f; dst_vtx->gl_tc[1] = curSeg.texcoord; - //FIXME VK applyBrightness( brightness, color, dst_vtx->color ); - // FIXME VK pglNormal3fv( vLastNormal ); + applyBrightness( brightness, dst_vtx->color ); VectorCopy( vPoint1, dst_vtx->pos ); + VectorCopy( vLastNormal, dst_vtx->normal ); ++dst_vtx; dst_vtx->lm_tc[0] = dst_vtx->lm_tc[1] = 0.f; dst_vtx->gl_tc[0] = 1.0f; dst_vtx->gl_tc[1] = curSeg.texcoord; - //FIXME VK applyBrightness( brightness, color, dst_vtx->color ); - // FIXME VK pglNormal3fv( vLastNormal ); + applyBrightness( brightness, dst_vtx->color ); VectorCopy( vPoint2, dst_vtx->pos ); + VectorCopy( vLastNormal, dst_vtx->normal ); ++dst_vtx; } @@ -397,11 +404,8 @@ static void R_DrawSegs( vec3_t source, vec3_t delta, float width, float scale, f } } -static void R_DrawTorus( vec3_t source, vec3_t delta, float width, float scale, float freq, float speed, int segments ) +static void R_DrawTorus( vec3_t source, vec3_t delta, float width, float scale, float freq, float speed, int segments, const vec4_t color ) { - PRINT_NOT_IMPLEMENTED(); - -/* FIXME VK int i, noiseIndex, noiseStep; float div, length, fraction, factor, vLast, vStep; vec3_t last1, last2, point, screen, screenLast, tmp, normal; @@ -427,6 +431,8 @@ static void R_DrawTorus( vec3_t source, vec3_t delta, float width, float scale, noiseStep = (int)((float)( NOISE_DIVISIONS - 1 ) * div * 65536.0f ); noiseIndex = 0; + TriBegin( TRI_TRIANGLE_STRIP ); + for( i = 0; i < segments; i++ ) { float s, c; @@ -480,14 +486,12 @@ static void R_DrawTorus( vec3_t source, vec3_t delta, float width, float scale, VectorCopy( screen, screenLast ); noiseIndex += noiseStep; } -*/ + + TriEndEx(color, "beam torus"); } -static void R_DrawDisk( vec3_t source, vec3_t delta, float width, float scale, float freq, float speed, int segments ) +static void R_DrawDisk( vec3_t source, vec3_t delta, float width, float scale, float freq, float speed, int segments, const vec4_t color ) { - PRINT_NOT_IMPLEMENTED(); - -/* FIXME VK float div, length, fraction; float w, vLast, vStep; vec3_t point; @@ -511,6 +515,8 @@ static void R_DrawDisk( vec3_t source, vec3_t delta, float width, float scale, f // clamp the beam width w = fmod( freq, width * 0.1f ) * delta[2]; + TriBegin( TRI_TRIANGLE_STRIP ); + // NOTE: we must force the degenerate triangles to be on the edge for( i = 0; i < segments; i++ ) { @@ -534,14 +540,12 @@ static void R_DrawDisk( vec3_t source, vec3_t delta, float width, float scale, f vLast += vStep; // advance texture scroll (v axis only) } - */ + + TriEndEx(color, "beam disk"); } -static void R_DrawCylinder( vec3_t source, vec3_t delta, float width, float scale, float freq, float speed, int segments ) +static void R_DrawCylinder( vec3_t source, vec3_t delta, float width, float scale, float freq, float speed, int segments, const vec4_t color ) { - PRINT_NOT_IMPLEMENTED(); - -/* FIXME VK float div, length, fraction; float vLast, vStep; vec3_t point; @@ -563,6 +567,7 @@ static void R_DrawCylinder( vec3_t source, vec3_t delta, float width, float scal vLast = fmod( freq * speed, 1 ); scale = scale * length; + TriBegin( TRI_TRIANGLE_STRIP ); for ( i = 0; i < segments; i++ ) { float s, c; @@ -588,14 +593,11 @@ static void R_DrawCylinder( vec3_t source, vec3_t delta, float width, float scal vLast += vStep; // Advance texture scroll (v axis only) } -*/ + TriEndEx(color, "beam cylinder"); } -static void R_DrawBeamFollow( BEAM *pbeam, float frametime ) +static void R_DrawBeamFollow( BEAM *pbeam, float frametime, const vec4_t color ) { - PRINT_NOT_IMPLEMENTED(); - -/* FIXME VK particle_t *pnew, *particles; float fraction, div, vLast, vStep; vec3_t last1, last2, tmp, screen; @@ -680,6 +682,7 @@ static void R_DrawBeamFollow( BEAM *pbeam, float frametime ) vLast = 0.0f; vStep = 1.0f; + TriBegin( TRI_QUADS ); while( particles ) { TriBrightness( fraction ); @@ -735,14 +738,12 @@ static void R_DrawBeamFollow( BEAM *pbeam, float frametime ) VectorMA( particles->org, frametime, particles->vel, particles->org ); particles = particles->next; } -*/ + + TriEndEx(color, "beam follow"); } -static void R_DrawRing( vec3_t source, vec3_t delta, float width, float amplitude, float freq, float speed, int segments ) +static void R_DrawRing( vec3_t source, vec3_t delta, float width, float amplitude, float freq, float speed, int segments, const vec4_t color ) { - PRINT_NOT_IMPLEMENTED(); - -/* FIXME VK int i, j, noiseIndex, noiseStep; float div, length, fraction, factor, vLast, vStep; vec3_t last1, last2, point, screen, screenLast; @@ -786,6 +787,7 @@ static void R_DrawRing( vec3_t source, vec3_t delta, float width, float amplitud VectorAdd( center, last1, tmp ); // maxs VectorSubtract( center, last1, screen ); // mins + /* FIXME VK if( !WORLDMODEL ) return; @@ -794,6 +796,7 @@ static void R_DrawRing( vec3_t source, vec3_t delta, float width, float amplitud { return; } + */ VectorSet( yaxis, xaxis[1], -xaxis[0], 0.0f ); VectorNormalize( yaxis ); @@ -801,6 +804,7 @@ static void R_DrawRing( vec3_t source, vec3_t delta, float width, float amplitud j = segments / 8; + TriBegin( TRI_TRIANGLE_STRIP ); for( i = 0; i < segments + 1; i++ ) { fraction = i * div; @@ -854,7 +858,7 @@ static void R_DrawRing( vec3_t source, vec3_t delta, float width, float amplitud FracNoise( rgNoise, NOISE_DIVISIONS ); } } -*/ + TriEndEx( color, "beam ring" ); } /* @@ -1110,31 +1114,34 @@ void R_BeamDraw( BEAM *pbeam, float frametime ) // TODO gl renderer has per-vertex color that is updated using brightness and whatever VK_RenderDebugLabelBegin( "beam" ); + TriSetTexture( texturenum ); + TriRenderMode( render_mode ); + TriColor4f( color[0], color[1], color[2], color[3] ); + switch( pbeam->type ) { case TE_BEAMTORUS: // FIXME VK GL_Cull( GL_NONE ); - R_DrawTorus( pbeam->source, pbeam->delta, pbeam->width, pbeam->amplitude, pbeam->freq, pbeam->speed, pbeam->segments ); + R_DrawTorus( pbeam->source, pbeam->delta, pbeam->width, pbeam->amplitude, pbeam->freq, pbeam->speed, pbeam->segments, color ); break; case TE_BEAMDISK: // FIXME VK GL_Cull( GL_NONE ); - R_DrawDisk( pbeam->source, pbeam->delta, pbeam->width, pbeam->amplitude, pbeam->freq, pbeam->speed, pbeam->segments ); + R_DrawDisk( pbeam->source, pbeam->delta, pbeam->width, pbeam->amplitude, pbeam->freq, pbeam->speed, pbeam->segments, color ); break; case TE_BEAMCYLINDER: // FIXME VK GL_Cull( GL_NONE ); - R_DrawCylinder( pbeam->source, pbeam->delta, pbeam->width, pbeam->amplitude, pbeam->freq, pbeam->speed, pbeam->segments ); + R_DrawCylinder( pbeam->source, pbeam->delta, pbeam->width, pbeam->amplitude, pbeam->freq, pbeam->speed, pbeam->segments, color ); break; case TE_BEAMPOINTS: case TE_BEAMHOSE: R_DrawSegs( pbeam->source, pbeam->delta, pbeam->width, pbeam->amplitude, pbeam->freq, pbeam->speed, pbeam->segments, pbeam->flags, color, texturenum, render_mode ); break; case TE_BEAMFOLLOW: - // FIXME VK TriBegin( TRI_QUADS ); - R_DrawBeamFollow( pbeam, frametime ); + R_DrawBeamFollow( pbeam, frametime, color ); break; case TE_BEAMRING: // FIXME VK GL_Cull( GL_NONE ); - R_DrawRing( pbeam->source, pbeam->delta, pbeam->width, pbeam->amplitude, pbeam->freq, pbeam->speed, pbeam->segments ); + R_DrawRing( pbeam->source, pbeam->delta, pbeam->width, pbeam->amplitude, pbeam->freq, pbeam->speed, pbeam->segments, color ); break; } diff --git a/ref/vk/vk_brush.c b/ref/vk/vk_brush.c index 6d527394..8b45aaa7 100644 --- a/ref/vk/vk_brush.c +++ b/ref/vk/vk_brush.c @@ -169,6 +169,8 @@ static void EmitWaterPolys( const cl_entity_t *ent, const msurface_t *warp, qboo poly_vertices[i].lm_tc[0] = 0; poly_vertices[i].lm_tc[1] = 0; + Vector4Set(poly_vertices[i].color, 255, 255, 255, 255); + #define WATER_NORMALS poly_vertices[i].normal[0] = 0; poly_vertices[i].normal[1] = 0; @@ -654,6 +656,8 @@ static qboolean loadBrushSurfaces( model_sizes_t sizes, const model_t *mod ) { vertex.lm_tc[0] = s; vertex.lm_tc[1] = t; + Vector4Set(vertex.color, 255, 255, 255, 255); + *(bvert++) = vertex; // Ray tracing apparently expects triangle list only (although spec is not very clear about this kekw) diff --git a/ref/vk/vk_geometry.h b/ref/vk/vk_geometry.h index 24388443..90aa31d9 100644 --- a/ref/vk/vk_geometry.h +++ b/ref/vk/vk_geometry.h @@ -14,15 +14,14 @@ // TODO is this a good place? typedef struct vk_vertex_s { // TODO padding needed for storage buffer reading, figure out how to fix in GLSL/SPV side - vec3_t pos; float p0_; - vec3_t prev_pos; float p01_; - vec3_t normal; uint32_t flags; - vec3_t tangent; uint32_t p1_; + vec3_t pos; float pad0_; + vec3_t prev_pos; float pad1_; + vec3_t normal; uint32_t pad2_; + vec3_t tangent; uint32_t pad3_; vec2_t gl_tc; //float p2_[2]; vec2_t lm_tc; //float p3_[2]; - - rgba_t color; // per-vertex (non-rt lighting) color, color[3] == 1(255) => use color, discard lightmap; color[3] == 0 => use lightmap, discard color - float _padding[3]; + rgba_t color; + float pad4_[3]; } vk_vertex_t; typedef struct { diff --git a/ref/vk/vk_render.c b/ref/vk/vk_render.c index f15aa879..224db005 100644 --- a/ref/vk/vk_render.c +++ b/ref/vk/vk_render.c @@ -87,7 +87,6 @@ static qboolean createPipelines( void ) {.binding = 0, .location = 2, .format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(vk_vertex_t, gl_tc)}, {.binding = 0, .location = 3, .format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(vk_vertex_t, lm_tc)}, {.binding = 0, .location = 4, .format = VK_FORMAT_R8G8B8A8_UNORM, .offset = offsetof(vk_vertex_t, color)}, - {.binding = 0, .location = 5, .format = VK_FORMAT_R32_UINT, .offset = offsetof(vk_vertex_t, flags)}, {.binding = 0, .location = 6, .format = VK_FORMAT_R32G32B32_SFLOAT, .offset = offsetof(vk_vertex_t, prev_pos)}, }; diff --git a/ref/vk/vk_rmain.c b/ref/vk/vk_rmain.c index 4dd7b177..bc746113 100644 --- a/ref/vk/vk_rmain.c +++ b/ref/vk/vk_rmain.c @@ -11,6 +11,8 @@ #include "vk_studio.h" #include "vk_beams.h" #include "vk_brush.h" +#include "vk_rpart.h" +#include "vk_triapi.h" #include "xash3d_types.h" #include "com_strings.h" @@ -174,16 +176,6 @@ static qboolean Mod_ProcessRenderData( model_t *mod, qboolean create, const byte return loaded; } -// efx implementation -static void CL_DrawParticles( double frametime, particle_t *particles, float partsize ) -{ - PRINT_NOT_IMPLEMENTED(); -} -static void CL_DrawTracers( double frametime, particle_t *tracers ) -{ - PRINT_NOT_IMPLEMENTED(); -} - // Xash3D Render Interface // Get renderer info (doesn't changes engine state at all) @@ -309,9 +301,13 @@ static void AVI_UploadRawFrame( int texture, int cols, int rows, int width, int } // glState related calls (must use this instead of normal gl-calls to prevent de-synchornize local states between engine and the client) -static void GL_Bind( int tmu, unsigned int texnum ) +static void GL_Bind( int tmu, unsigned int texnum ) { - PRINT_NOT_IMPLEMENTED(); + if (tmu != 0) { + PRINT_NOT_IMPLEMENTED_ARGS("non-zero tmu=%d", tmu); + } + + TriSetTexture(texnum); } static void GL_SelectTexture( int tmu ) { @@ -386,35 +382,6 @@ static void* R_GetProcAddress( const char *name ) } // TriAPI Interface -// NOTE: implementation isn't required to be compatible -static void TriRenderMode( int mode ) -{ - PRINT_NOT_IMPLEMENTED(); -} -static void TriBegin( int primitiveCode ) -{ - PRINT_NOT_IMPLEMENTED(); -} -static void TriEnd( void ) -{ - PRINT_NOT_IMPLEMENTED(); -} -static void TriColor4f( float r, float g, float b, float a ) -{ - PRINT_NOT_IMPLEMENTED(); -} -static void TriTexCoord2f( float u, float v ) -{ - PRINT_NOT_IMPLEMENTED(); -} -static void TriVertex3fv( const float *worldPnt ) -{ - PRINT_NOT_IMPLEMENTED(); -} -static void TriVertex3f( float x, float y, float z ) -{ - PRINT_NOT_IMPLEMENTED(); -} static void TriFog( float flFogColor[3], float flStart, float flEnd, int bOn ) { PRINT_NOT_IMPLEMENTED(); diff --git a/ref/vk/vk_rpart.c b/ref/vk/vk_rpart.c new file mode 100644 index 00000000..aa892fd5 --- /dev/null +++ b/ref/vk/vk_rpart.c @@ -0,0 +1,310 @@ +/* +cl_part.c - particles and tracers +Copyright (C) 2010 Uncle Mike + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. +*/ + +#include "vk_rpart.h" +#include "vk_triapi.h" +#include "camera.h" +#include "vk_textures.h" // tglob.particleTexture +#include "vk_common.h" +#include "vk_sprite.h" // R_GetSpriteTexture + +#include "xash3d_types.h" // vec3_t for r_efx.h +#include "const.h" // color24 for r_efx.h +#include "r_efx.h" +#include "event_flags.h" +#include "entity_types.h" +#include "triangleapi.h" +#include "pm_local.h" +#include "studio.h" +#include "pm_movevars.h" // movevars_t + +static float gTracerSize[11] = { 1.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; +static color24 gTracerColors[] = +{ +{ 255, 255, 255 }, // White +{ 255, 0, 0 }, // Red +{ 0, 255, 0 }, // Green +{ 0, 0, 255 }, // Blue +{ 0, 0, 0 }, // Tracer default, filled in from cvars, etc. +{ 255, 167, 17 }, // Yellow-orange sparks +{ 255, 130, 90 }, // Yellowish streaks (garg) +{ 55, 60, 144 }, // Blue egon streak +{ 255, 130, 90 }, // More Yellowish streaks (garg) +{ 255, 140, 90 }, // More Yellowish streaks (garg) +{ 200, 130, 90 }, // More red streaks (garg) +{ 255, 120, 70 }, // Darker red streaks (garg) +}; + +/* +================ +CL_DrawParticles + +update particle color, position, free expired and draw it +================ +*/ +void CL_DrawParticles( double frametime, particle_t *cl_active_particles, float partsize ) +{ + particle_t *p; + vec3_t right, up; + color24 *pColor; + int alpha; + float size; + + if( !cl_active_particles ) + return; // nothing to draw? + + TriRenderMode( kRenderTransAlpha ); + TriSetTexture( tglob.particleTexture ); + + TriBegin( TRI_QUADS ); + + for( p = cl_active_particles; p; p = p->next ) + { + if(( p->type != pt_blob ) || ( p->packedColor == 255 )) + { + size = partsize; // get initial size of particle + + // scale up to keep particles from disappearing + // FIXME are these really the same? + vec3_t cull_vforward, cull_vup, cull_vright; + VectorCopy(g_camera.vforward, cull_vforward); + VectorCopy(g_camera.vup, cull_vup); + VectorCopy(g_camera.vright, cull_vright); + size += (p->org[0] - g_camera.vieworg[0]) * cull_vforward[0]; + size += (p->org[1] - g_camera.vieworg[1]) * cull_vforward[1]; + size += (p->org[2] - g_camera.vieworg[2]) * cull_vforward[2]; + + if( size < 20.0f ) size = partsize; + else size = partsize + size * 0.002f; + + // scale the axes by radius + VectorScale( cull_vright, size, right ); + VectorScale( cull_vup, size, up ); + + p->color = bound( 0, p->color, 255 ); + pColor = gEngine.CL_GetPaletteColor( p->color ); + + alpha = 255 * (p->die - gpGlobals->time) * 16.0f; + if( alpha > 255 || p->type == pt_static ) + alpha = 255; + + TriColor4ub_( gEngine.LightToTexGamma( pColor->r ), + gEngine.LightToTexGamma( pColor->g ), + gEngine.LightToTexGamma( pColor->b ), alpha ); + + TriTexCoord2f( 0.0f, 1.0f ); + TriVertex3f( p->org[0] - right[0] + up[0], p->org[1] - right[1] + up[1], p->org[2] - right[2] + up[2] ); + TriTexCoord2f( 0.0f, 0.0f ); + TriVertex3f( p->org[0] + right[0] + up[0], p->org[1] + right[1] + up[1], p->org[2] + right[2] + up[2] ); + TriTexCoord2f( 1.0f, 0.0f ); + TriVertex3f( p->org[0] + right[0] - up[0], p->org[1] + right[1] - up[1], p->org[2] + right[2] - up[2] ); + TriTexCoord2f( 1.0f, 1.0f ); + TriVertex3f( p->org[0] - right[0] - up[0], p->org[1] - right[1] - up[1], p->org[2] - right[2] - up[2] ); + } + + gEngine.CL_ThinkParticle( frametime, p ); + } + + const vec4_t color = { 1, 1, 1, 1 }; // pColor->r / 255.f, pColor->g / 255.f, pColor->b / 255.f, 1.f }; + TriEndEx( color, "particle"); +} + +/* +================ +CL_CullTracer + +check tracer bbox +================ +*/ +static qboolean CL_CullTracer( particle_t *p, const vec3_t start, const vec3_t end ) +{ + vec3_t mins, maxs; + int i; + + // compute the bounding box + for( i = 0; i < 3; i++ ) + { + if( start[i] < end[i] ) + { + mins[i] = start[i]; + maxs[i] = end[i]; + } + else + { + mins[i] = end[i]; + maxs[i] = start[i]; + } + + // don't let it be zero sized + if( mins[i] == maxs[i] ) + { + maxs[i] += gTracerSize[p->type] * 2.0f; + } + } + + // check bbox + return false; // FIXME VK R_CullBox( mins, maxs ); +} + +/* +================ +CL_DrawTracers + +update tracer color, position, free expired and draw it +================ +*/ +void CL_DrawTracers( double frametime, particle_t *cl_active_tracers ) +{ + float scale, atten, gravity; + vec3_t screenLast, screen; + vec3_t start, end, delta; + particle_t *p; + + /* FIXME VK + // update tracer color if this is changed + if( FBitSet( tracerred->flags|tracergreen->flags|tracerblue->flags|traceralpha->flags, FCVAR_CHANGED )) + { + color24 *customColors = &gTracerColors[4]; + customColors->r = (byte)(tracerred->value * traceralpha->value * 255); + customColors->g = (byte)(tracergreen->value * traceralpha->value * 255); + customColors->b = (byte)(tracerblue->value * traceralpha->value * 255); + ClearBits( tracerred->flags, FCVAR_CHANGED ); + ClearBits( tracergreen->flags, FCVAR_CHANGED ); + ClearBits( tracerblue->flags, FCVAR_CHANGED ); + ClearBits( traceralpha->flags, FCVAR_CHANGED ); + } + */ + + if( !cl_active_tracers ) + return; // nothing to draw? + + if( !TriSpriteTexture( gEngine.GetDefaultSprite( REF_DOT_SPRITE ), 0 )) + return; + + TriRenderMode( kRenderTransAdd ); + +#define MOVEVARS (gEngine.pfnGetMoveVars()) + gravity = frametime * MOVEVARS->gravity; + scale = 1.0 - (frametime * 0.9); + if( scale < 0.0f ) scale = 0.0f; + + for( p = cl_active_tracers; p; p = p->next ) + { + atten = (p->die - gpGlobals->time); + if( atten > 0.1f ) atten = 0.1f; + + VectorScale( p->vel, ( p->ramp * atten ), delta ); + VectorAdd( p->org, delta, end ); + VectorCopy( p->org, start ); + + if( !CL_CullTracer( p, start, end )) + { + vec3_t verts[4], tmp2; + vec3_t tmp, normal; + color24 *pColor; + + // Transform point into screen space + TriWorldToScreen( start, screen ); + TriWorldToScreen( end, screenLast ); + + // build world-space normal to screen-space direction vector + VectorSubtract( screen, screenLast, tmp ); + + // we don't need Z, we're in screen space + tmp[2] = 0; + VectorNormalize( tmp ); + + vec3_t cull_vforward, cull_vup, cull_vright; + VectorCopy(g_camera.vforward, cull_vforward); + VectorCopy(g_camera.vup, cull_vup); + VectorCopy(g_camera.vright, cull_vright); + + // build point along noraml line (normal is -y, x) + VectorScale( cull_vup, tmp[0] * gTracerSize[p->type], normal ); + VectorScale( cull_vright, -tmp[1] * gTracerSize[p->type], tmp2 ); + VectorSubtract( normal, tmp2, normal ); + + // compute four vertexes + VectorSubtract( start, normal, verts[0] ); + VectorAdd( start, normal, verts[1] ); + VectorAdd( verts[0], delta, verts[2] ); + VectorAdd( verts[1], delta, verts[3] ); + + if( p->color > sizeof( gTracerColors ) / sizeof( color24 ) ) + { + gEngine.Con_Printf( S_ERROR "UserTracer with color > %d\n", (int)(sizeof( gTracerColors ) / sizeof( color24 ))); + p->color = 0; + } + + pColor = &gTracerColors[p->color]; + TriColor4ub_( pColor->r, pColor->g, pColor->b, p->packedColor ); + + TriBegin( TRI_QUADS ); + TriTexCoord2f( 0.0f, 0.8f ); + TriVertex3fv( verts[2] ); + TriTexCoord2f( 1.0f, 0.8f ); + TriVertex3fv( verts[3] ); + TriTexCoord2f( 1.0f, 0.0f ); + TriVertex3fv( verts[1] ); + TriTexCoord2f( 0.0f, 0.0f ); + TriVertex3fv( verts[0] ); + const vec4_t color = { 1, 1, 1, 1 }; //pColor->r / 255.f, pColor->g / 255.f, pColor->b / 255.f, p->packedColor / 255.f }; + TriEndEx( color, "tracer" ); + } + + // evaluate position + VectorMA( p->org, frametime, p->vel, p->org ); + + if( p->type == pt_grav ) + { + p->vel[0] *= scale; + p->vel[1] *= scale; + p->vel[2] -= gravity; + + p->packedColor = 255 * (p->die - gpGlobals->time) * 2; + if( p->packedColor > 255 ) p->packedColor = 255; + } + else if( p->type == pt_slowgrav ) + { + p->vel[2] = gravity * 0.05f; + } + } +} + +/* +=============== +CL_DrawParticlesExternal + +allow to draw effects from custom renderer +=============== +*/ + +/* FIXME VK +void CL_DrawParticlesExternal( const ref_viewpass_t *rvp, qboolean trans_pass, float frametime ) +{ + ref_instance_t oldRI = RI; + + memcpy( &oldRI, &RI, sizeof( ref_instance_t )); + R_SetupRefParams( rvp ); + R_SetupFrustum(); + R_SetuTri( false ); // don't touch GL-states + tr.frametime = frametime; + + gEngfuncs.CL_DrawEFX( frametime, trans_pass ); + + // restore internal state + memcpy( &RI, &oldRI, sizeof( ref_instance_t )); +} +*/ diff --git a/ref/vk/vk_rpart.h b/ref/vk/vk_rpart.h new file mode 100644 index 00000000..a325de3f --- /dev/null +++ b/ref/vk/vk_rpart.h @@ -0,0 +1,6 @@ +#pragma once + +typedef struct particle_s particle_t; + +void CL_DrawParticles( double frametime, particle_t *particles, float partsize ); +void CL_DrawTracers( double frametime, particle_t *tracers ); diff --git a/ref/vk/vk_sprite.c b/ref/vk/vk_sprite.c index 35988d6c..56d8705e 100644 --- a/ref/vk/vk_sprite.c +++ b/ref/vk/vk_sprite.c @@ -679,7 +679,6 @@ static void R_DrawSpriteQuad( const char *debug_name, mspriteframe_t *frame, vec dst_vtx[0].gl_tc[0] = 0.f; dst_vtx[0].gl_tc[1] = 1.f; dst_vtx[0].lm_tc[0] = dst_vtx[0].lm_tc[1] = 0.f; - dst_vtx[0].flags = 1; // vertex lighting instead of lightmap lighting Vector4Set(dst_vtx[0].color, 255, 255, 255, 255); VectorCopy(v_normal, dst_vtx[0].normal); @@ -688,7 +687,6 @@ static void R_DrawSpriteQuad( const char *debug_name, mspriteframe_t *frame, vec dst_vtx[1].gl_tc[0] = 0.f; dst_vtx[1].gl_tc[1] = 0.f; dst_vtx[1].lm_tc[0] = dst_vtx[1].lm_tc[1] = 0.f; - dst_vtx[1].flags = 1; // vertex lighting instead of lightmap lighting Vector4Set(dst_vtx[1].color, 255, 255, 255, 255); VectorCopy(v_normal, dst_vtx[1].normal); @@ -697,7 +695,6 @@ static void R_DrawSpriteQuad( const char *debug_name, mspriteframe_t *frame, vec dst_vtx[2].gl_tc[0] = 1.f; dst_vtx[2].gl_tc[1] = 0.f; dst_vtx[2].lm_tc[0] = dst_vtx[2].lm_tc[1] = 0.f; - dst_vtx[2].flags = 1; // vertex lighting instead of lightmap lighting Vector4Set(dst_vtx[2].color, 255, 255, 255, 255); VectorCopy(v_normal, dst_vtx[2].normal); @@ -706,7 +703,6 @@ static void R_DrawSpriteQuad( const char *debug_name, mspriteframe_t *frame, vec dst_vtx[3].gl_tc[0] = 1.f; dst_vtx[3].gl_tc[1] = 1.f; dst_vtx[3].lm_tc[0] = dst_vtx[3].lm_tc[1] = 0.f; - dst_vtx[3].flags = 1; // vertex lighting instead of lightmap lighting Vector4Set(dst_vtx[3].color, 255, 255, 255, 255); VectorCopy(v_normal, dst_vtx[3].normal); diff --git a/ref/vk/vk_studio.c b/ref/vk/vk_studio.c index 64ffb833..0fb4f897 100644 --- a/ref/vk/vk_studio.c +++ b/ref/vk/vk_studio.c @@ -1932,7 +1932,6 @@ static void R_StudioDrawNormalMesh( short *ptricmds, vec3_t *pstudionorms, float dst_vtx->gl_tc[1] = ptricmds[3] * t; } - dst_vtx->flags = 1; // vertex lighting instead of lightmap lighting R_StudioSetColorBegin( ptricmds, pstudionorms, dst_vtx->color ); if (j > 1) { diff --git a/ref/vk/vk_triapi.c b/ref/vk/vk_triapi.c new file mode 100644 index 00000000..79b44c2b --- /dev/null +++ b/ref/vk/vk_triapi.c @@ -0,0 +1,233 @@ +#include "vk_triapi.h" +#include "vk_geometry.h" +#include "vk_render.h" +#include "vk_sprite.h" // R_GetSpriteTexture + +#include "vk_textures.h" // FIXME temp + +#include "xash3d_mathlib.h" + +#define MAX_TRIAPI_VERTICES 1024 +#define MAX_TRIAPI_INDICES 4096 + +static struct { + vk_vertex_t vertices[MAX_TRIAPI_VERTICES]; + uint16_t indices[MAX_TRIAPI_INDICES]; + + int num_vertices; + int primitive_mode; + int texture_index; + + vk_render_type_e render_type; + + qboolean initialized; +} g_triapi = {0}; + +void TriSetTexture( int texture_index ) { + g_triapi.texture_index = texture_index; +} + +int TriSpriteTexture( model_t *pSpriteModel, int frame ) +{ + int gl_texturenum; + + if(( gl_texturenum = R_GetSpriteTexture( pSpriteModel, frame )) <= 0 ) + return 0; + + TriSetTexture( gl_texturenum ); + + return 1; +} + +void TriRenderMode( int render_mode ) { + switch( render_mode ) + { + case kRenderTransAlpha: g_triapi.render_type = kVkRenderType_A_1mA_R; break; + case kRenderTransColor: + case kRenderTransTexture: g_triapi.render_type = kVkRenderType_A_1mA_RW; break; + case kRenderGlow: + case kRenderTransAdd: g_triapi.render_type = kVkRenderType_A_1_R; break; + case kRenderNormal: + default: g_triapi.render_type = kVkRenderTypeSolid; break; + } +} + +void TriBegin( int primitive_mode ) { + ASSERT(!g_triapi.primitive_mode); + + switch(primitive_mode) { + case TRI_TRIANGLES: break; + case TRI_TRIANGLE_STRIP: break; + case TRI_QUADS: break; + default: + gEngine.Con_Printf(S_ERROR "TriBegin: unsupported primitive_mode %d\n", primitive_mode); + return; + } + + vk_vertex_t *const ve = g_triapi.vertices + 0; + if (g_triapi.num_vertices > 1) + *ve = g_triapi.vertices[g_triapi.num_vertices-1]; + + if (!g_triapi.initialized) { + Vector4Set(ve->color, 255, 255, 255, 255); + g_triapi.initialized = true; + } + + g_triapi.primitive_mode = primitive_mode + 1; + g_triapi.num_vertices = 0; +} + +/* static int genTrianglesIndices(void) { */ +/* return 0; */ +/* } */ + +static int genQuadsIndices(void) { + int num_indices = 0; + uint16_t *const dst_idx = g_triapi.indices; + for (int i = 0; i < g_triapi.num_vertices - 3; i+=4) { + if (num_indices > MAX_TRIAPI_INDICES - 6) { + gEngine.Con_Printf(S_ERROR "Triapi ran out of indices space, max %d (vertices=%d)\n", MAX_TRIAPI_INDICES, g_triapi.num_vertices); + break; + } + + dst_idx[num_indices++] = 0 + i; + dst_idx[num_indices++] = 1 + i; + dst_idx[num_indices++] = 2 + i; + + dst_idx[num_indices++] = 0 + i; + dst_idx[num_indices++] = 2 + i; + dst_idx[num_indices++] = 3 + i; + } + return num_indices; +} + +static int genTriangleStripIndices(void) { + int num_indices = 0; + uint16_t *const dst_idx = g_triapi.indices; + for (int i = 2; i < g_triapi.num_vertices; ++i) { + if (num_indices > MAX_TRIAPI_INDICES - 3) { + gEngine.Con_Printf(S_ERROR "Triapi ran out of indices space, max %d (vertices=%d)\n", MAX_TRIAPI_INDICES, g_triapi.num_vertices); + break; + } + + if( i & 1 ) + { + // draw triangle [n-1 n-2 n] + dst_idx[num_indices++] = i - 1; + dst_idx[num_indices++] = i - 2; + dst_idx[num_indices++] = i; + } + else + { + // draw triangle [n-2 n-1 n] + dst_idx[num_indices++] = i - 2; + dst_idx[num_indices++] = i - 1; + dst_idx[num_indices++] = i; + } + } + return num_indices; +} + +static void emitDynamicGeometry(int num_indices, const vec4_t color, const char* name ) { + if (!num_indices) + return; + + r_geometry_buffer_lock_t buffer; + if (!R_GeometryBufferAllocAndLock( &buffer, g_triapi.num_vertices, num_indices, LifetimeSingleFrame )) { + gEngine.Con_Printf(S_ERROR "Cannot allocate geometry for tri api\n"); + return; + } + + memcpy(buffer.vertices.ptr, g_triapi.vertices, sizeof(vk_vertex_t) * g_triapi.num_vertices); + memcpy(buffer.indices.ptr, g_triapi.indices, sizeof(uint16_t) * num_indices); + + R_GeometryBufferUnlock( &buffer ); + + { + const vk_render_geometry_t geometry = { + .texture = g_triapi.texture_index, + .material = (g_triapi.render_type == kVkRenderTypeSolid) ? kXVkMaterialRegular : kXVkMaterialEmissive, + + .max_vertex = g_triapi.num_vertices, + .vertex_offset = buffer.vertices.unit_offset, + + .element_count = num_indices, + .index_offset = buffer.indices.unit_offset, + + .emissive = { color[0], color[1], color[2] }, + }; + + VK_RenderModelDynamicBegin( g_triapi.render_type, color, name ); + VK_RenderModelDynamicAddGeometry( &geometry ); + VK_RenderModelDynamicCommit(); + } +} + +void TriEnd( void ) { + if (!g_triapi.primitive_mode) + return; + + const vk_vertex_t *const v = g_triapi.vertices + g_triapi.num_vertices - 1; + const vec4_t color = {v->color[0] / 255.f, v->color[1] / 255.f, v->color[2] / 255.f, 1.f}; + TriEndEx( color, "unnamed triapi" ); +} + +void TriEndEx( const vec4_t color, const char* name ) { + if (!g_triapi.primitive_mode) + return; + + int num_indices = 0; + switch(g_triapi.primitive_mode - 1) { + /* case TRI_TRIANGLES: */ + /* num_indices = genTrianglesIndices(); */ + /* break; */ + case TRI_TRIANGLE_STRIP: num_indices = genTriangleStripIndices(); break; + case TRI_QUADS: num_indices = genQuadsIndices(); break; + default: + gEngine.Con_Printf(S_ERROR "TriEnd: unsupported primitive_mode %d\n", g_triapi.primitive_mode - 1); + break; + } + + emitDynamicGeometry(num_indices, color, name); + + g_triapi.num_vertices = 0; + g_triapi.primitive_mode = 0; +} + +void TriTexCoord2f( float u, float v ) { + vk_vertex_t *const ve = g_triapi.vertices + g_triapi.num_vertices; + Vector2Set(ve->gl_tc, u, v); +} + +void TriVertex3fv( const float *v ) { + TriVertex3f(v[0], v[1], v[2]); +} + +void TriVertex3f( float x, float y, float z ) { + if (g_triapi.num_vertices == MAX_TRIAPI_VERTICES - 1) { + gEngine.Con_Printf(S_ERROR "vk TriApi: trying to emit more than %d vertices in one batch\n", MAX_TRIAPI_VERTICES); + return; + } + + vk_vertex_t *const ve = g_triapi.vertices + g_triapi.num_vertices; + VectorSet(ve->pos, x, y, z); + + // Emit vertex preserving previous vertex values + ++g_triapi.num_vertices; + g_triapi.vertices[g_triapi.num_vertices] = g_triapi.vertices[g_triapi.num_vertices-1]; +} + +static int clampi32(int v, int min, int max) { + if (v < min) return min; + if (v > max) return max; + return v; +} + +void TriColor4ub_( byte r, byte g, byte b, byte a ) { + Vector4Set(g_triapi.vertices[g_triapi.num_vertices].color, r, g, b, a); +} + +void TriColor4f( float r, float g, float b, float a ) { + TriColor4ub_(clampi32(r*255.f, 0, 255),clampi32(g*255.f, 0, 255),clampi32(b*255.f, 0, 255),clampi32(a*255.f, 0, 255)); +} + diff --git a/ref/vk/vk_triapi.h b/ref/vk/vk_triapi.h new file mode 100644 index 00000000..a1a38a34 --- /dev/null +++ b/ref/vk/vk_triapi.h @@ -0,0 +1,22 @@ +#pragma once + +#include "xash3d_types.h" + +typedef struct model_s model_t; + +void TriRenderMode( int mode ); +void TriSetTexture( int texture_index ); +int TriSpriteTexture( model_t *pSpriteModel, int frame ); + +void TriBegin( int mode ); + +void TriTexCoord2f( float u, float v ); +void TriColor4f( float r, float g, float b, float a ); +void TriColor4ub_( byte r, byte g, byte b, byte a ); // FIXME consolidate with vk_renderstate + +// Emits next vertex +void TriVertex3fv( const float *v ); +void TriVertex3f( float x, float y, float z ); + +void TriEnd( void ); +void TriEndEx( const vec4_t color, const char* name );