diff options
Diffstat (limited to 'servers')
-rw-r--r-- | servers/audio/effects/audio_effect_pitch_shift.cpp | 96 | ||||
-rw-r--r-- | servers/audio/effects/audio_effect_pitch_shift.h | 41 | ||||
-rw-r--r-- | servers/physics_server_2d.cpp | 2 | ||||
-rw-r--r-- | servers/physics_server_3d.cpp | 2 | ||||
-rw-r--r-- | servers/rendering/rasterizer_dummy.h | 1 | ||||
-rw-r--r-- | servers/rendering/renderer_rd/renderer_scene_render_rd.cpp | 15 | ||||
-rw-r--r-- | servers/rendering/renderer_rd/renderer_scene_sky_rd.h | 2 | ||||
-rw-r--r-- | servers/rendering/renderer_rd/renderer_storage_rd.cpp | 91 | ||||
-rw-r--r-- | servers/rendering/renderer_rd/renderer_storage_rd.h | 17 | ||||
-rw-r--r-- | servers/rendering/renderer_rd/shaders/particles.glsl | 18 | ||||
-rw-r--r-- | servers/rendering/renderer_rd/shaders/particles_copy.glsl | 36 | ||||
-rw-r--r-- | servers/rendering/renderer_scene_cull.cpp | 9 | ||||
-rw-r--r-- | servers/rendering/renderer_storage.h | 1 | ||||
-rw-r--r-- | servers/rendering/shader_types.cpp | 12 | ||||
-rw-r--r-- | servers/text/text_server_extension.cpp | 15 | ||||
-rw-r--r-- | servers/text/text_server_extension.h | 5 | ||||
-rw-r--r-- | servers/text_server.cpp | 11 | ||||
-rw-r--r-- | servers/text_server.h | 14 |
18 files changed, 286 insertions, 102 deletions
diff --git a/servers/audio/effects/audio_effect_pitch_shift.cpp b/servers/audio/effects/audio_effect_pitch_shift.cpp index 3c53887931..ba2d257c0a 100644 --- a/servers/audio/effects/audio_effect_pitch_shift.cpp +++ b/servers/audio/effects/audio_effect_pitch_shift.cpp @@ -74,7 +74,7 @@ * *****************************************************************************/ -void SMBPitchShift::PitchShift(float pitchShift, long numSampsToProcess, long fftFrameSize, long osamp, float sampleRate, float *indata, float *outdata,int stride) { +void SMBPitchShift::PitchShift(float pitchShift, int64_t numSampsToProcess, int64_t fftFrameSize, int64_t osamp, float sampleRate, float *indata, float *outdata,int stride) { /* @@ -85,19 +85,32 @@ void SMBPitchShift::PitchShift(float pitchShift, long numSampsToProcess, long ff */ double magn, phase, tmp, window, real, imag; - double freqPerBin, expct; - long i,k, qpd, index, inFifoLatency, stepSize, fftFrameSize2; + double freqPerBin, expct, reciprocalFftFrameSize; + int64_t i,k, qpd, index, inFifoLatency, stepSize, fftFrameSize2; /* set up some handy variables */ fftFrameSize2 = fftFrameSize/2; + reciprocalFftFrameSize = 1./fftFrameSize; stepSize = fftFrameSize/osamp; - freqPerBin = sampleRate/(double)fftFrameSize; - expct = 2.*Math_PI*(double)stepSize/(double)fftFrameSize; + freqPerBin = reciprocalFftFrameSize * sampleRate; + expct = Math_TAU * reciprocalFftFrameSize * stepSize; inFifoLatency = fftFrameSize-stepSize; - if (gRover == 0) { gRover = inFifoLatency; -} + if (gRover == 0) { + gRover = inFifoLatency; + } - /* initialize our static arrays */ + // If pitchShift changes clear arrays to prevent some artifacts and quality loss. + if (lastPitchShift != pitchShift) { + lastPitchShift = pitchShift; + memset(gInFIFO, 0, MAX_FRAME_LENGTH * sizeof(float)); + memset(gOutFIFO, 0, MAX_FRAME_LENGTH * sizeof(float)); + memset(gFFTworksp, 0, 2 * MAX_FRAME_LENGTH * sizeof(double)); + memset(gLastPhase, 0, (MAX_FRAME_LENGTH / 2 + 1) * sizeof(double)); + memset(gSumPhase, 0, (MAX_FRAME_LENGTH / 2 + 1) * sizeof(double)); + memset(gOutputAccum, 0, 2 * MAX_FRAME_LENGTH * sizeof(double)); + memset(gAnaFreq, 0, MAX_FRAME_LENGTH * sizeof(double)); + memset(gAnaMagn, 0, MAX_FRAME_LENGTH * sizeof(double)); + } /* main processing loop */ for (i = 0; i < numSampsToProcess; i++){ @@ -112,7 +125,7 @@ void SMBPitchShift::PitchShift(float pitchShift, long numSampsToProcess, long ff /* do windowing and re,im interleave */ for (k = 0; k < fftFrameSize;k++) { - window = -.5*cos(2.*Math_PI*(double)k/(double)fftFrameSize)+.5; + window = -.5*cos(Math_TAU * reciprocalFftFrameSize * k)+.5; gFFTworksp[2*k] = gInFIFO[k] * window; gFFTworksp[2*k+1] = 0.; } @@ -124,6 +137,7 @@ void SMBPitchShift::PitchShift(float pitchShift, long numSampsToProcess, long ff /* this is the analysis step */ for (k = 0; k <= fftFrameSize2; k++) { + /* de-interlace FFT buffer */ real = gFFTworksp[2*k]; imag = gFFTworksp[2*k+1]; @@ -141,13 +155,15 @@ void SMBPitchShift::PitchShift(float pitchShift, long numSampsToProcess, long ff /* map delta phase into +/- Pi interval */ qpd = tmp/Math_PI; - if (qpd >= 0) { qpd += qpd&1; - } else { qpd -= qpd&1; -} + if (qpd >= 0) { + qpd += qpd&1; + } else { + qpd -= qpd&1; + } tmp -= Math_PI*(double)qpd; /* get deviation from bin frequency from the +/- Pi interval */ - tmp = osamp*tmp/(2.*Math_PI); + tmp = osamp*tmp/Math_TAU; /* compute the k-th partials' true frequency */ tmp = (double)k*freqPerBin + tmp*freqPerBin; @@ -160,8 +176,8 @@ void SMBPitchShift::PitchShift(float pitchShift, long numSampsToProcess, long ff /* ***************** PROCESSING ******************* */ /* this does the actual pitch shifting */ - memset(gSynMagn, 0, fftFrameSize*sizeof(float)); - memset(gSynFreq, 0, fftFrameSize*sizeof(float)); + memset(gSynMagn, 0, fftFrameSize*sizeof(double)); + memset(gSynFreq, 0, fftFrameSize*sizeof(double)); for (k = 0; k <= fftFrameSize2; k++) { index = k*pitchShift; if (index <= fftFrameSize2) { @@ -184,7 +200,7 @@ void SMBPitchShift::PitchShift(float pitchShift, long numSampsToProcess, long ff tmp /= freqPerBin; /* take osamp into account */ - tmp = 2.*Math_PI*tmp/osamp; + tmp = Math_TAU*tmp/osamp; /* add the overlap phase advance back in */ tmp += (double)k*expct; @@ -199,33 +215,35 @@ void SMBPitchShift::PitchShift(float pitchShift, long numSampsToProcess, long ff } /* zero negative frequencies */ - for (k = fftFrameSize+2; k < 2*fftFrameSize; k++) { gFFTworksp[k] = 0.; -} + for (k = fftFrameSize+2; k < 2*MAX_FRAME_LENGTH; k++) { + gFFTworksp[k] = 0.; + } /* do inverse transform */ smbFft(gFFTworksp, fftFrameSize, 1); /* do windowing and add to output accumulator */ for(k=0; k < fftFrameSize; k++) { - window = -.5*cos(2.*Math_PI*(double)k/(double)fftFrameSize)+.5; + window = -.5*cos(Math_TAU * reciprocalFftFrameSize * k)+.5; gOutputAccum[k] += 2.*window*gFFTworksp[2*k]/(fftFrameSize2*osamp); } - for (k = 0; k < stepSize; k++) { gOutFIFO[k] = gOutputAccum[k]; -} + for (k = 0; k < stepSize; k++) { + gOutFIFO[k] = gOutputAccum[k]; + } /* shift accumulator */ - memmove(gOutputAccum, gOutputAccum+stepSize, fftFrameSize*sizeof(float)); + memmove(gOutputAccum, gOutputAccum+stepSize, fftFrameSize*sizeof(double)); /* move input FIFO */ - for (k = 0; k < inFifoLatency; k++) { gInFIFO[k] = gInFIFO[k+stepSize]; -} + for (k = 0; k < inFifoLatency; k++) { + gInFIFO[k] = gInFIFO[k+stepSize]; + } } } } - -void SMBPitchShift::smbFft(float *fftBuffer, long fftFrameSize, long sign) +void SMBPitchShift::smbFft(double *fftBuffer, int64_t fftFrameSize, int64_t sign) /* FFT routine, (C)1996 S.M.Bernsee. Sign = -1 is FFT, 1 is iFFT (inverse) Fills fftBuffer[0...2*fftFrameSize-1] with the Fourier transform of the @@ -238,14 +256,16 @@ void SMBPitchShift::smbFft(float *fftBuffer, long fftFrameSize, long sign) of the frequencies of interest is in fftBuffer[0...fftFrameSize]. */ { - float wr, wi, arg, *p1, *p2, temp; - float tr, ti, ur, ui, *p1r, *p1i, *p2r, *p2i; - long i, bitm, j, le, le2, k; + double wr, wi, arg, *p1, *p2, temp; + double tr, ti, ur, ui, *p1r, *p1i, *p2r, *p2i; + int64_t i, bitm, j, le, le2, k, logN; + logN = (int64_t)(log(fftFrameSize) / log(2.) + .5); for (i = 2; i < 2*fftFrameSize-2; i += 2) { for (bitm = 2, j = 0; bitm < 2*fftFrameSize; bitm <<= 1) { - if (i & bitm) { j++; -} + if (i & bitm) { + j++; + } j <<= 1; } if (i < j) { @@ -255,7 +275,8 @@ void SMBPitchShift::smbFft(float *fftBuffer, long fftFrameSize, long sign) *p1 = *p2; *p2 = temp; } } - for (k = 0, le = 2; k < (long)(log((double)fftFrameSize)/log(2.)+.5); k++) { + + for (k = 0, le = 2; k < logN; k++) { le <<= 1; le2 = le>>1; ur = 1.0; @@ -288,6 +309,14 @@ void SMBPitchShift::smbFft(float *fftBuffer, long fftFrameSize, long sign) void AudioEffectPitchShiftInstance::process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) { float sample_rate = AudioServer::get_singleton()->get_mix_rate(); + // For pitch_scale 1.0 it's cheaper to just pass samples without processing them. + if (Math::is_equal_approx(base->pitch_scale, 1.0f)) { + for (int i = 0; i < p_frame_count; i++) { + p_dst_frames[i] = p_src_frames[i]; + } + return; + } + float *in_l = (float *)p_src_frames; float *in_r = in_l + 1; @@ -361,7 +390,4 @@ AudioEffectPitchShift::AudioEffectPitchShift() { pitch_scale = 1.0; oversampling = 4; fft_size = FFT_SIZE_2048; - wet = 0.0; - dry = 0.0; - filter = false; } diff --git a/servers/audio/effects/audio_effect_pitch_shift.h b/servers/audio/effects/audio_effect_pitch_shift.h index 0478d05ceb..23da61bb32 100644 --- a/servers/audio/effects/audio_effect_pitch_shift.h +++ b/servers/audio/effects/audio_effect_pitch_shift.h @@ -40,31 +40,33 @@ class SMBPitchShift { float gInFIFO[MAX_FRAME_LENGTH]; float gOutFIFO[MAX_FRAME_LENGTH]; - float gFFTworksp[2 * MAX_FRAME_LENGTH]; - float gLastPhase[MAX_FRAME_LENGTH / 2 + 1]; - float gSumPhase[MAX_FRAME_LENGTH / 2 + 1]; - float gOutputAccum[2 * MAX_FRAME_LENGTH]; - float gAnaFreq[MAX_FRAME_LENGTH]; - float gAnaMagn[MAX_FRAME_LENGTH]; - float gSynFreq[MAX_FRAME_LENGTH]; - float gSynMagn[MAX_FRAME_LENGTH]; - long gRover; - - void smbFft(float *fftBuffer, long fftFrameSize, long sign); + double gFFTworksp[2 * MAX_FRAME_LENGTH]; + double gLastPhase[MAX_FRAME_LENGTH / 2 + 1]; + double gSumPhase[MAX_FRAME_LENGTH / 2 + 1]; + double gOutputAccum[2 * MAX_FRAME_LENGTH]; + double gAnaFreq[MAX_FRAME_LENGTH]; + double gAnaMagn[MAX_FRAME_LENGTH]; + double gSynFreq[MAX_FRAME_LENGTH]; + double gSynMagn[MAX_FRAME_LENGTH]; + int64_t gRover; + float lastPitchShift; + + void smbFft(double *fftBuffer, int64_t fftFrameSize, int64_t sign); public: - void PitchShift(float pitchShift, long numSampsToProcess, long fftFrameSize, long osamp, float sampleRate, float *indata, float *outdata, int stride); + void PitchShift(float pitchShift, int64_t numSampsToProcess, int64_t fftFrameSize, int64_t osamp, float sampleRate, float *indata, float *outdata, int stride); SMBPitchShift() { gRover = 0; memset(gInFIFO, 0, MAX_FRAME_LENGTH * sizeof(float)); memset(gOutFIFO, 0, MAX_FRAME_LENGTH * sizeof(float)); - memset(gFFTworksp, 0, 2 * MAX_FRAME_LENGTH * sizeof(float)); - memset(gLastPhase, 0, (MAX_FRAME_LENGTH / 2 + 1) * sizeof(float)); - memset(gSumPhase, 0, (MAX_FRAME_LENGTH / 2 + 1) * sizeof(float)); - memset(gOutputAccum, 0, 2 * MAX_FRAME_LENGTH * sizeof(float)); - memset(gAnaFreq, 0, MAX_FRAME_LENGTH * sizeof(float)); - memset(gAnaMagn, 0, MAX_FRAME_LENGTH * sizeof(float)); + memset(gFFTworksp, 0, 2 * MAX_FRAME_LENGTH * sizeof(double)); + memset(gLastPhase, 0, (MAX_FRAME_LENGTH / 2 + 1) * sizeof(double)); + memset(gSumPhase, 0, (MAX_FRAME_LENGTH / 2 + 1) * sizeof(double)); + memset(gOutputAccum, 0, 2 * MAX_FRAME_LENGTH * sizeof(double)); + memset(gAnaFreq, 0, MAX_FRAME_LENGTH * sizeof(double)); + memset(gAnaMagn, 0, MAX_FRAME_LENGTH * sizeof(double)); + lastPitchShift = 1.0; } }; @@ -101,9 +103,6 @@ public: float pitch_scale; int oversampling; FFTSize fft_size; - float wet; - float dry; - bool filter; protected: static void _bind_methods(); diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp index d8f2a2a780..45816e3244 100644 --- a/servers/physics_server_2d.cpp +++ b/servers/physics_server_2d.cpp @@ -336,6 +336,8 @@ Dictionary PhysicsDirectSpaceState2D::_intersect_ray(const Ref<PhysicsRayQueryPa } Array PhysicsDirectSpaceState2D::_intersect_point(const Ref<PhysicsPointQueryParameters2D> &p_point_query, int p_max_results) { + ERR_FAIL_COND_V(p_point_query.is_null(), Array()); + Vector<ShapeResult> ret; ret.resize(p_max_results); diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp index 8fafd07f87..fc119e49e9 100644 --- a/servers/physics_server_3d.cpp +++ b/servers/physics_server_3d.cpp @@ -339,6 +339,8 @@ Dictionary PhysicsDirectSpaceState3D::_intersect_ray(const Ref<PhysicsRayQueryPa } Array PhysicsDirectSpaceState3D::_intersect_point(const Ref<PhysicsPointQueryParameters3D> &p_point_query, int p_max_results) { + ERR_FAIL_COND_V(p_point_query.is_null(), Array()); + Vector<ShapeResult> ret; ret.resize(p_max_results); diff --git a/servers/rendering/rasterizer_dummy.h b/servers/rendering/rasterizer_dummy.h index be374f1a21..74c080660d 100644 --- a/servers/rendering/rasterizer_dummy.h +++ b/servers/rendering/rasterizer_dummy.h @@ -560,6 +560,7 @@ public: void particles_set_speed_scale(RID p_particles, double p_scale) override {} void particles_set_use_local_coordinates(RID p_particles, bool p_enable) override {} void particles_set_process_material(RID p_particles, RID p_material) override {} + RID particles_get_process_material(RID p_particles) const override { return RID(); } void particles_set_fixed_fps(RID p_particles, int p_fps) override {} void particles_set_interpolate(RID p_particles, bool p_enable) override {} void particles_set_fractional_delta(RID p_particles, bool p_enable) override {} diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 2d34d2a2a0..948340f469 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -1818,11 +1818,14 @@ void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) { if (rb->blur[i].mipmaps[m].fb.is_valid()) { RD::get_singleton()->free(rb->blur[i].mipmaps[m].fb); } - if (rb->blur[i].mipmaps[m].half_fb.is_valid()) { - RD::get_singleton()->free(rb->blur[i].mipmaps[m].half_fb); - } - if (rb->blur[i].mipmaps[m].half_texture.is_valid()) { - RD::get_singleton()->free(rb->blur[i].mipmaps[m].half_texture); + // texture and framebuffer in both blur mipmaps are shared, so only free from the first one + if (i == 0) { + if (rb->blur[i].mipmaps[m].half_fb.is_valid()) { + RD::get_singleton()->free(rb->blur[i].mipmaps[m].half_fb); + } + if (rb->blur[i].mipmaps[m].half_texture.is_valid()) { + RD::get_singleton()->free(rb->blur[i].mipmaps[m].half_texture); + } } } rb->blur[i].mipmaps.clear(); @@ -3283,7 +3286,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const RS::LightType type = storage->light_get_type(base); switch (type) { case RS::LIGHT_DIRECTIONAL: { - if (r_directional_light_count >= cluster.max_directional_lights) { + if (r_directional_light_count >= cluster.max_directional_lights || storage->light_directional_is_sky_only(base)) { continue; } diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h index 13d24e2508..7b6c813d90 100644 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h @@ -254,7 +254,7 @@ public: int radiance_size = 256; - RS::SkyMode mode = RS::SKY_MODE_AUTOMATIC; + RS::SkyMode mode = RS::SKY_MODE_REALTIME; ReflectionData reflection; bool dirty = false; diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index f345001539..e3829eb5ed 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp @@ -3578,15 +3578,15 @@ void RendererStorageRD::mesh_instance_set_blend_shape_weight(RID p_mesh_instance void RendererStorageRD::_mesh_instance_clear(MeshInstance *mi) { for (uint32_t i = 0; i < mi->surfaces.size(); i++) { - if (mi->surfaces[i].vertex_buffer.is_valid()) { - RD::get_singleton()->free(mi->surfaces[i].vertex_buffer); - } if (mi->surfaces[i].versions) { for (uint32_t j = 0; j < mi->surfaces[i].version_count; j++) { RD::get_singleton()->free(mi->surfaces[i].versions[j].vertex_array); } memfree(mi->surfaces[i].versions); } + if (mi->surfaces[i].vertex_buffer.is_valid()) { + RD::get_singleton()->free(mi->surfaces[i].vertex_buffer); + } } mi->surfaces.clear(); @@ -4522,6 +4522,8 @@ void RendererStorageRD::_particles_free_data(Particles *particles) { particles->particle_instance_buffer = RID(); } + particles->userdata_count = 0; + if (particles->frame_params_buffer.is_valid()) { RD::get_singleton()->free(particles->frame_params_buffer); particles->frame_params_buffer = RID(); @@ -4716,6 +4718,14 @@ void RendererStorageRD::particles_set_process_material(RID p_particles, RID p_ma ERR_FAIL_COND(!particles); particles->process_material = p_material; + particles->dependency.changed_notify(DEPENDENCY_CHANGED_PARTICLES); //the instance buffer may have changed +} + +RID RendererStorageRD::particles_get_process_material(RID p_particles) const { + Particles *particles = particles_owner.get_or_null(p_particles); + ERR_FAIL_COND_V(!particles, RID()); + + return particles->process_material; } void RendererStorageRD::particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) { @@ -4852,10 +4862,13 @@ AABB RendererStorageRD::particles_get_current_aabb(RID p_particles) { if (buffer.size()) { bool first = true; - const ParticleData *particle_data = reinterpret_cast<const ParticleData *>(buffer.ptr()); + const uint8_t *data_ptr = (const uint8_t *)buffer.ptr(); + uint32_t particle_data_size = sizeof(ParticleData) + sizeof(float) * particles->userdata_count; + for (int i = 0; i < total_amount; i++) { - if (particle_data[i].active) { - Vector3 pos = Vector3(particle_data[i].xform[12], particle_data[i].xform[13], particle_data[i].xform[14]); + const ParticleData &particle_data = *(const ParticleData *)&data_ptr[particle_data_size * i]; + if (particle_data.active) { + Vector3 pos = Vector3(particle_data.xform[12], particle_data.xform[13], particle_data.xform[14]); if (!particles->use_local_coords) { pos = inv.xform(pos); } @@ -5420,6 +5433,7 @@ void RendererStorageRD::particles_set_view_axis(RID p_particles, const Vector3 & copy_push_constant.frame_remainder = particles->interpolate ? particles->frame_remainder : 0.0; copy_push_constant.total_particles = particles->amount; + copy_push_constant.copy_mode_2d = false; Vector3 axis = -p_axis; // cameras look to z negative @@ -5440,7 +5454,7 @@ void RendererStorageRD::particles_set_view_axis(RID p_particles, const Vector3 & if (do_sort) { RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[ParticlesShader::COPY_MODE_FILL_SORT_BUFFER]); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[ParticlesShader::COPY_MODE_FILL_SORT_BUFFER + particles->userdata_count * ParticlesShader::COPY_MODE_MAX]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_sort_uniform_set, 1); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->trail_bind_pose_uniform_set, 2); @@ -5455,7 +5469,10 @@ void RendererStorageRD::particles_set_view_axis(RID p_particles, const Vector3 & copy_push_constant.total_particles *= copy_push_constant.total_particles; RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[do_sort ? ParticlesShader::COPY_MODE_FILL_INSTANCES_WITH_SORT_BUFFER : (particles->mode == RS::PARTICLES_MODE_2D ? ParticlesShader::COPY_MODE_FILL_INSTANCES_2D : ParticlesShader::COPY_MODE_FILL_INSTANCES)]); + uint32_t copy_pipeline = do_sort ? ParticlesShader::COPY_MODE_FILL_INSTANCES_WITH_SORT_BUFFER : ParticlesShader::COPY_MODE_FILL_INSTANCES; + copy_pipeline += particles->userdata_count * ParticlesShader::COPY_MODE_MAX; + copy_push_constant.copy_mode_2d = particles->mode == RS::PARTICLES_MODE_2D ? 1 : 0; + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[copy_pipeline]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0); if (do_sort) { RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_sort_uniform_set, 1); @@ -5470,6 +5487,19 @@ void RendererStorageRD::particles_set_view_axis(RID p_particles, const Vector3 & } void RendererStorageRD::_particles_update_buffers(Particles *particles) { + uint32_t userdata_count = 0; + + const Material *material = material_owner.get_or_null(particles->process_material); + if (material && material->shader && material->shader->data) { + const ParticlesShaderData *shader_data = static_cast<const ParticlesShaderData *>(material->shader->data); + userdata_count = shader_data->userdata_count; + } + + if (userdata_count != particles->userdata_count) { + // Mismatch userdata, re-create buffers. + _particles_free_data(particles); + } + if (particles->amount > 0 && particles->particle_buffer.is_null()) { int total_amount = particles->amount; if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) { @@ -5478,7 +5508,9 @@ void RendererStorageRD::_particles_update_buffers(Particles *particles) { uint32_t xform_size = particles->mode == RS::PARTICLES_MODE_2D ? 2 : 3; - particles->particle_buffer = RD::get_singleton()->storage_buffer_create(sizeof(ParticleData) * total_amount); + particles->particle_buffer = RD::get_singleton()->storage_buffer_create((sizeof(ParticleData) + userdata_count * sizeof(float) * 4) * total_amount); + + particles->userdata_count = userdata_count; particles->particle_instance_buffer = RD::get_singleton()->storage_buffer_create(sizeof(float) * 4 * (xform_size + 1 + 1) * total_amount); //needs to clear it @@ -5702,7 +5734,8 @@ void RendererStorageRD::update_particles() { copy_push_constant.lifetime_reverse = particles->draw_order == RS::PARTICLES_DRAW_ORDER_REVERSE_LIFETIME; RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[particles->mode == RS::PARTICLES_MODE_2D ? ParticlesShader::COPY_MODE_FILL_INSTANCES_2D : ParticlesShader::COPY_MODE_FILL_INSTANCES]); + copy_push_constant.copy_mode_2d = particles->mode == RS::PARTICLES_MODE_2D ? 1 : 0; + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, particles_shader.copy_pipelines[ParticlesShader::COPY_MODE_FILL_INSTANCES + particles->userdata_count * ParticlesShader::COPY_MODE_MAX]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->particles_copy_uniform_set, 0); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, particles->trail_bind_pose_uniform_set, 2); RD::get_singleton()->compute_list_set_push_constant(compute_list, ©_push_constant, sizeof(ParticlesShader::CopyPushConstant)); @@ -5754,6 +5787,12 @@ void RendererStorageRD::ParticlesShaderData::set_code(const String &p_code) { actions.usage_flag_pointers["COLLIDED"] = &uses_collision; + userdata_count = 0; + for (uint32_t i = 0; i < ParticlesShader::MAX_USERDATAS; i++) { + userdatas_used[i] = false; + actions.usage_flag_pointers["USERDATA" + itos(i + 1)] = &userdatas_used[i]; + } + actions.uniforms = &uniforms; Error err = base_singleton->particles_shader.compiler.compile(RS::SHADER_PARTICLES, code, &actions, path, gen_code); @@ -5763,6 +5802,12 @@ void RendererStorageRD::ParticlesShaderData::set_code(const String &p_code) { version = base_singleton->particles_shader.shader.version_create(); } + for (uint32_t i = 0; i < ParticlesShader::MAX_USERDATAS; i++) { + if (userdatas_used[i]) { + userdata_count++; + } + } + base_singleton->particles_shader.shader.version_set_compute_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_COMPUTE], gen_code.defines); ERR_FAIL_COND(!base_singleton->particles_shader.shader.version_is_valid(version)); @@ -9930,6 +9975,11 @@ RendererStorageRD::RendererStorageRD() { actions.renames["ACTIVE"] = "particle_active"; actions.renames["RESTART"] = "restart"; actions.renames["CUSTOM"] = "PARTICLE.custom"; + for (int i = 0; i < ParticlesShader::MAX_USERDATAS; i++) { + String udname = "USERDATA" + itos(i + 1); + actions.renames[udname] = "PARTICLE.userdata" + itos(i + 1); + actions.usage_defines[udname] = "#define USERDATA" + itos(i + 1) + "_USED\n"; + } actions.renames["TRANSFORM"] = "PARTICLE.xform"; actions.renames["TIME"] = "frame_history.data[0].time"; actions.renames["PI"] = _MKSTR(Math_PI); @@ -10034,17 +10084,26 @@ void process() { { Vector<String> copy_modes; - copy_modes.push_back("\n#define MODE_FILL_INSTANCES\n"); - copy_modes.push_back("\n#define MODE_FILL_INSTANCES\n#define MODE_2D\n"); - copy_modes.push_back("\n#define MODE_FILL_SORT_BUFFER\n#define USE_SORT_BUFFER\n"); - copy_modes.push_back("\n#define MODE_FILL_INSTANCES\n#define USE_SORT_BUFFER\n"); + for (int i = 0; i <= ParticlesShader::MAX_USERDATAS; i++) { + if (i == 0) { + copy_modes.push_back("\n#define MODE_FILL_INSTANCES\n"); + copy_modes.push_back("\n#define MODE_FILL_SORT_BUFFER\n#define USE_SORT_BUFFER\n"); + copy_modes.push_back("\n#define MODE_FILL_INSTANCES\n#define USE_SORT_BUFFER\n"); + } else { + copy_modes.push_back("\n#define MODE_FILL_INSTANCES\n#define USERDATA_COUNT " + itos(i) + "\n"); + copy_modes.push_back("\n#define MODE_FILL_SORT_BUFFER\n#define USE_SORT_BUFFER\n#define USERDATA_COUNT " + itos(i) + "\n"); + copy_modes.push_back("\n#define MODE_FILL_INSTANCES\n#define USE_SORT_BUFFER\n#define USERDATA_COUNT " + itos(i) + "\n"); + } + } particles_shader.copy_shader.initialize(copy_modes); particles_shader.copy_shader_version = particles_shader.copy_shader.version_create(); - for (int i = 0; i < ParticlesShader::COPY_MODE_MAX; i++) { - particles_shader.copy_pipelines[i] = RD::get_singleton()->compute_pipeline_create(particles_shader.copy_shader.version_get_shader(particles_shader.copy_shader_version, i)); + for (int i = 0; i <= ParticlesShader::MAX_USERDATAS; i++) { + for (int j = 0; j < ParticlesShader::COPY_MODE_MAX; j++) { + particles_shader.copy_pipelines[i * ParticlesShader::COPY_MODE_MAX + j] = RD::get_singleton()->compute_pipeline_create(particles_shader.copy_shader.version_get_shader(particles_shader.copy_shader_version, i * ParticlesShader::COPY_MODE_MAX + j)); + } } } diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h index 6febb71e93..ee4d18210a 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.h +++ b/servers/rendering/renderer_rd/renderer_storage_rd.h @@ -751,6 +751,8 @@ private: RID particle_instance_buffer; RID frame_params_buffer; + uint32_t userdata_count = 0; + RID particles_material_uniform_set; RID particles_copy_uniform_set; RID particles_transforms_buffer_uniform_set; @@ -849,12 +851,14 @@ private: uint32_t order_by_lifetime; uint32_t lifetime_split; uint32_t lifetime_reverse; - uint32_t pad; + uint32_t copy_mode_2d; }; enum { + MAX_USERDATAS = 6 + }; + enum { COPY_MODE_FILL_INSTANCES, - COPY_MODE_FILL_INSTANCES_2D, COPY_MODE_FILL_SORT_BUFFER, COPY_MODE_FILL_INSTANCES_WITH_SORT_BUFFER, COPY_MODE_MAX, @@ -862,7 +866,7 @@ private: ParticlesCopyShaderRD copy_shader; RID copy_shader_version; - RID copy_pipelines[COPY_MODE_MAX]; + RID copy_pipelines[COPY_MODE_MAX * (MAX_USERDATAS + 1)]; LocalVector<float> pose_update_buffer; @@ -888,7 +892,10 @@ private: RID pipeline; - bool uses_time; + bool uses_time = false; + + bool userdatas_used[ParticlesShader::MAX_USERDATAS] = {}; + uint32_t userdata_count = 0; virtual void set_code(const String &p_Code); virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index); @@ -2162,6 +2169,8 @@ public: void particles_set_speed_scale(RID p_particles, double p_scale); void particles_set_use_local_coordinates(RID p_particles, bool p_enable); void particles_set_process_material(RID p_particles, RID p_material); + RID particles_get_process_material(RID p_particles) const; + void particles_set_fixed_fps(RID p_particles, int p_fps); void particles_set_interpolate(RID p_particles, bool p_enable); void particles_set_fractional_delta(RID p_particles, bool p_enable); diff --git a/servers/rendering/renderer_rd/shaders/particles.glsl b/servers/rendering/renderer_rd/shaders/particles.glsl index d691ea2fdf..1b1051ecfa 100644 --- a/servers/rendering/renderer_rd/shaders/particles.glsl +++ b/servers/rendering/renderer_rd/shaders/particles.glsl @@ -112,6 +112,24 @@ struct ParticleData { uint flags; vec4 color; vec4 custom; +#ifdef USERDATA1_USED + vec4 userdata1; +#endif +#ifdef USERDATA2_USED + vec4 userdata2; +#endif +#ifdef USERDATA3_USED + vec4 userdata3; +#endif +#ifdef USERDATA4_USED + vec4 userdata4; +#endif +#ifdef USERDATA5_USED + vec4 userdata5; +#endif +#ifdef USERDATA6_USED + vec4 userdata6; +#endif }; layout(set = 1, binding = 1, std430) restrict buffer Particles { diff --git a/servers/rendering/renderer_rd/shaders/particles_copy.glsl b/servers/rendering/renderer_rd/shaders/particles_copy.glsl index bb11e4c78d..b991880cd9 100644 --- a/servers/rendering/renderer_rd/shaders/particles_copy.glsl +++ b/servers/rendering/renderer_rd/shaders/particles_copy.glsl @@ -16,6 +16,9 @@ struct ParticleData { uint flags; vec4 color; vec4 custom; +#ifdef USERDATA_COUNT + vec4 userdata[USERDATA_COUNT]; +#endif }; layout(set = 0, binding = 1, std430) restrict readonly buffer Particles { @@ -57,7 +60,7 @@ layout(push_constant, std430) uniform Params { bool order_by_lifetime; uint lifetime_split; bool lifetime_reverse; - uint pad; + bool copy_mode_2d; } params; @@ -201,25 +204,22 @@ void main() { txform = mat4(vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0)); //zero scale, becomes invisible } -#ifdef MODE_2D - - uint write_offset = gl_GlobalInvocationID.x * (2 + 1 + 1); //xform + color + custom + if (params.copy_mode_2d) { + uint write_offset = gl_GlobalInvocationID.x * (2 + 1 + 1); //xform + color + custom - instances.data[write_offset + 0] = txform[0]; - instances.data[write_offset + 1] = txform[1]; - instances.data[write_offset + 2] = particles.data[particle].color; - instances.data[write_offset + 3] = particles.data[particle].custom; - -#else - - uint write_offset = gl_GlobalInvocationID.x * (3 + 1 + 1); //xform + color + custom + instances.data[write_offset + 0] = txform[0]; + instances.data[write_offset + 1] = txform[1]; + instances.data[write_offset + 2] = particles.data[particle].color; + instances.data[write_offset + 3] = particles.data[particle].custom; + } else { + uint write_offset = gl_GlobalInvocationID.x * (3 + 1 + 1); //xform + color + custom - instances.data[write_offset + 0] = txform[0]; - instances.data[write_offset + 1] = txform[1]; - instances.data[write_offset + 2] = txform[2]; - instances.data[write_offset + 3] = particles.data[particle].color; - instances.data[write_offset + 4] = particles.data[particle].custom; -#endif //MODE_2D + instances.data[write_offset + 0] = txform[0]; + instances.data[write_offset + 1] = txform[1]; + instances.data[write_offset + 2] = txform[2]; + instances.data[write_offset + 3] = particles.data[particle].color; + instances.data[write_offset + 4] = particles.data[particle].custom; + } #endif } diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 5b2be8e174..5bdc7ce600 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -3683,6 +3683,15 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) { _instance_update_mesh_instance(p_instance); } + if (p_instance->base_type == RS::INSTANCE_PARTICLES) { + // update the process material dependency + + RID particle_material = RSG::storage->particles_get_process_material(p_instance->base); + if (particle_material.is_valid()) { + RSG::storage->material_update_dependency(particle_material, &p_instance->dependency_tracker); + } + } + if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); diff --git a/servers/rendering/renderer_storage.h b/servers/rendering/renderer_storage.h index 43a7778d67..a2df7ad38e 100644 --- a/servers/rendering/renderer_storage.h +++ b/servers/rendering/renderer_storage.h @@ -477,6 +477,7 @@ public: virtual void particles_set_speed_scale(RID p_particles, double p_scale) = 0; virtual void particles_set_use_local_coordinates(RID p_particles, bool p_enable) = 0; virtual void particles_set_process_material(RID p_particles, RID p_material) = 0; + virtual RID particles_get_process_material(RID p_particles) const = 0; virtual void particles_set_fixed_fps(RID p_particles, int p_fps) = 0; virtual void particles_set_interpolate(RID p_particles, bool p_enable) = 0; virtual void particles_set_fractional_delta(RID p_particles, bool p_enable) = 0; diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp index b8bb211a7a..d628cf3713 100644 --- a/servers/rendering/shader_types.cpp +++ b/servers/rendering/shader_types.cpp @@ -318,6 +318,12 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["MASS"] = ShaderLanguage::TYPE_FLOAT; shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["ACTIVE"] = ShaderLanguage::TYPE_BOOL; shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["CUSTOM"] = ShaderLanguage::TYPE_VEC4; + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["USERDATA1"] = ShaderLanguage::TYPE_VEC4; + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["USERDATA2"] = ShaderLanguage::TYPE_VEC4; + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["USERDATA3"] = ShaderLanguage::TYPE_VEC4; + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["USERDATA4"] = ShaderLanguage::TYPE_VEC4; + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["USERDATA5"] = ShaderLanguage::TYPE_VEC4; + shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["USERDATA6"] = ShaderLanguage::TYPE_VEC4; shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["TRANSFORM"] = ShaderLanguage::TYPE_MAT4; shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["LIFETIME"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["DELTA"] = constt(ShaderLanguage::TYPE_FLOAT); @@ -338,6 +344,12 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["ACTIVE"] = ShaderLanguage::TYPE_BOOL; shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["RESTART"] = constt(ShaderLanguage::TYPE_BOOL); shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["CUSTOM"] = ShaderLanguage::TYPE_VEC4; + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["USERDATA1"] = ShaderLanguage::TYPE_VEC4; + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["USERDATA2"] = ShaderLanguage::TYPE_VEC4; + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["USERDATA3"] = ShaderLanguage::TYPE_VEC4; + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["USERDATA4"] = ShaderLanguage::TYPE_VEC4; + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["USERDATA5"] = ShaderLanguage::TYPE_VEC4; + shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["USERDATA6"] = ShaderLanguage::TYPE_VEC4; shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["TRANSFORM"] = ShaderLanguage::TYPE_MAT4; shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["LIFETIME"] = constt(ShaderLanguage::TYPE_FLOAT); shader_modes[RS::SHADER_PARTICLES].functions["process"].built_ins["DELTA"] = constt(ShaderLanguage::TYPE_FLOAT); diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp index 3c5faa4ef7..5792572dc1 100644 --- a/servers/text/text_server_extension.cpp +++ b/servers/text/text_server_extension.cpp @@ -85,6 +85,9 @@ void TextServerExtension::_bind_methods() { GDVIRTUAL_BIND(_font_set_hinting, "font_rid", "hinting"); GDVIRTUAL_BIND(_font_get_hinting, "font_rid"); + GDVIRTUAL_BIND(_font_set_subpixel_positioning, "font_rid", "subpixel_positioning"); + GDVIRTUAL_BIND(_font_get_subpixel_positioning, "font_rid"); + GDVIRTUAL_BIND(_font_set_variation_coordinates, "font_rid", "variation_coordinates"); GDVIRTUAL_BIND(_font_get_variation_coordinates, "font_rid"); @@ -512,6 +515,18 @@ TextServer::Hinting TextServerExtension::font_get_hinting(RID p_font_rid) const return TextServer::Hinting::HINTING_NONE; } +void TextServerExtension::font_set_subpixel_positioning(RID p_font_rid, TextServer::SubpixelPositioning p_subpixel) { + GDVIRTUAL_CALL(_font_set_subpixel_positioning, p_font_rid, p_subpixel); +} + +TextServer::SubpixelPositioning TextServerExtension::font_get_subpixel_positioning(RID p_font_rid) const { + TextServer::SubpixelPositioning ret; + if (GDVIRTUAL_CALL(_font_get_subpixel_positioning, p_font_rid, ret)) { + return (TextServer::SubpixelPositioning)ret; + } + return TextServer::SubpixelPositioning::SUBPIXEL_POSITIONING_DISABLED; +} + void TextServerExtension::font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) { GDVIRTUAL_CALL(_font_set_variation_coordinates, p_font_rid, p_variation_coordinates); } diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h index 9e7f666be1..d185e44806 100644 --- a/servers/text/text_server_extension.h +++ b/servers/text/text_server_extension.h @@ -134,6 +134,11 @@ public: GDVIRTUAL2(_font_set_hinting, RID, Hinting); GDVIRTUAL1RC(Hinting, _font_get_hinting, RID); + virtual void font_set_subpixel_positioning(RID p_font_rid, SubpixelPositioning p_subpixel) override; + virtual SubpixelPositioning font_get_subpixel_positioning(RID p_font_rid) const override; + GDVIRTUAL2(_font_set_subpixel_positioning, RID, SubpixelPositioning); + GDVIRTUAL1RC(SubpixelPositioning, _font_get_subpixel_positioning, RID); + virtual void font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) override; virtual Dictionary font_get_variation_coordinates(RID p_font_rid) const override; GDVIRTUAL2(_font_set_variation_coordinates, RID, Dictionary); diff --git a/servers/text_server.cpp b/servers/text_server.cpp index b7cd39b9b2..37cc6599b1 100644 --- a/servers/text_server.cpp +++ b/servers/text_server.cpp @@ -235,9 +235,12 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("font_set_force_autohinter", "font_rid", "force_autohinter"), &TextServer::font_set_force_autohinter); ClassDB::bind_method(D_METHOD("font_is_force_autohinter", "font_rid"), &TextServer::font_is_force_autohinter); - ClassDB::bind_method(D_METHOD("font_set_hinting", "font_rid", "_hinting"), &TextServer::font_set_hinting); + ClassDB::bind_method(D_METHOD("font_set_hinting", "font_rid", "hinting"), &TextServer::font_set_hinting); ClassDB::bind_method(D_METHOD("font_get_hinting", "font_rid"), &TextServer::font_get_hinting); + ClassDB::bind_method(D_METHOD("font_set_subpixel_positioning", "font_rid", "subpixel_positioning"), &TextServer::font_set_subpixel_positioning); + ClassDB::bind_method(D_METHOD("font_get_subpixel_positioning", "font_rid"), &TextServer::font_get_subpixel_positioning); + ClassDB::bind_method(D_METHOD("font_set_variation_coordinates", "font_rid", "variation_coordinates"), &TextServer::font_set_variation_coordinates); ClassDB::bind_method(D_METHOD("font_get_variation_coordinates", "font_rid"), &TextServer::font_get_variation_coordinates); @@ -479,6 +482,12 @@ void TextServer::_bind_methods() { BIND_ENUM_CONSTANT(HINTING_LIGHT); BIND_ENUM_CONSTANT(HINTING_NORMAL); + /* SubpixelPositioning */ + BIND_ENUM_CONSTANT(SUBPIXEL_POSITIONING_DISABLED); + BIND_ENUM_CONSTANT(SUBPIXEL_POSITIONING_AUTO); + BIND_ENUM_CONSTANT(SUBPIXEL_POSITIONING_ONE_HALF); + BIND_ENUM_CONSTANT(SUBPIXEL_POSITIONING_ONE_QUARTER); + /* Feature */ BIND_ENUM_CONSTANT(FEATURE_BIDI_LAYOUT); BIND_ENUM_CONSTANT(FEATURE_VERTICAL_LAYOUT); diff --git a/servers/text_server.h b/servers/text_server.h index 629a633b9f..38ad496490 100644 --- a/servers/text_server.h +++ b/servers/text_server.h @@ -101,6 +101,16 @@ public: HINTING_NORMAL }; + enum SubpixelPositioning { + SUBPIXEL_POSITIONING_DISABLED, + SUBPIXEL_POSITIONING_AUTO, + SUBPIXEL_POSITIONING_ONE_HALF, + SUBPIXEL_POSITIONING_ONE_QUARTER, + }; + + const int SUBPIXEL_POSITIONING_ONE_HALF_MAX_SIZE = 20; + const int SUBPIXEL_POSITIONING_ONE_QUARTER_MAX_SIZE = 16; + enum Feature { FEATURE_BIDI_LAYOUT = 1 << 0, FEATURE_VERTICAL_LAYOUT = 1 << 1, @@ -248,6 +258,9 @@ public: virtual void font_set_hinting(RID p_font_rid, Hinting p_hinting) = 0; virtual Hinting font_get_hinting(RID p_font_rid) const = 0; + virtual void font_set_subpixel_positioning(RID p_font_rid, SubpixelPositioning p_subpixel) = 0; + virtual SubpixelPositioning font_get_subpixel_positioning(RID p_font_rid) const = 0; + virtual void font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) = 0; virtual Dictionary font_get_variation_coordinates(RID p_font_rid) const = 0; @@ -551,6 +564,7 @@ VARIANT_ENUM_CAST(TextServer::LineBreakFlag); VARIANT_ENUM_CAST(TextServer::TextOverrunFlag); VARIANT_ENUM_CAST(TextServer::GraphemeFlag); VARIANT_ENUM_CAST(TextServer::Hinting); +VARIANT_ENUM_CAST(TextServer::SubpixelPositioning); VARIANT_ENUM_CAST(TextServer::Feature); VARIANT_ENUM_CAST(TextServer::ContourPointTag); VARIANT_ENUM_CAST(TextServer::SpacingType); |